一、超声波测距模块HC-SR04
1、产品特色
①典型工作用电压:5V
②超小静态工作电流:小于 5mA
③感应角度(R3 电阻越大,增益越高,探测角度越大):
R3 电阻为 392,不大于 15 度
R3 电阻为 472, 不大于 30 度
④探测距离(R3 电阻可调节增益,即调节探测距离):
R3 电阻为 392 2cm-450cm
R3 电阻为 472 2cm-700cm
⑤高精度:可达 0.3cm
⑥盲区(2cm)超近
2、产品实物图
3、接口定义
Vcc
Trig(控制端)
Echo(接收端)
Gnd
控制口发一个 10US 以上的高电平,就可以在接收口等待高电平输出。一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离.如此不断的周期测,就可以达到你移动测量的值了。
二、模块工作原理
1、原理
①采用 IO 触发测距,给至少10us 的高电平信号;
②模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
③有信号返回,通过 IO 输出一高电平,高电平持续的时间就是
④
测试距离=(高电平时间*声速(340M/S))/2;
2、超声波时序图
以上时序图表明你只需要提供一个10us 以上脉冲触发信号,该模块内部将发出8个40kHz周期电平并检测回波。一旦检测到有回波信号则输出回响信号。回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。公式:us/58=厘米或者us/148-英寸;或是:距离=高电平时间*声速(340M/S)/2;建议测量周期为60ms 以上,以防止发射信号对回响信号的影响。
三、Verilog实现
`timescale 1ns / 1ps
module HC_SR04(
input clk , //50M系统时钟
input rst_n, //系统复位 低电平有效
input echo , // 超声波接受端口
output trig , //超声波控制端口
output beep //蜂鸣器
);
parameter idle=3'b001, //空闲状态
s0=3'b010, //计回响信号的时间
s1=3'b100; //清零 转移最终数值
///状态编码 独热码
parameter ms_100ms=750+(50_000*100); //15us 超过10us的高电平 100ms 50_000*100
reg [23:0] trig_cnt; //控制计数
reg [2:0] cur_state; //定义状态寄存器
reg [2:0] next_state;
reg [24:0] echo_cnt ; //计算回响信号高电平的持续时间
reg [24:0] echo_cnt_reg; //保存回响信号高电平持续的时间
wire [24:0] dis; //超声波测量的距离
always@(posedge clk)begin
if(!rst_n)
trig_cnt<=0;
else if(trig_cnt==ms_100ms-1) //当计数记到最大值时 清零
trig_cnt<=0;
else
trig_cnt<=trig_cnt+1;
end
assign trig=(trig_cnt>0 && trig_cnt<750)?1:0;
/发送触发信号
always@(posedge clk)begin
if(!rst_n)
cur_state<=idle;
else
cur_state<=next_state;
end
always@(*)begin
case(cur_state)
idle:begin
if(echo==1)
next_state=s0;
else
next_state=idle;
end
s0:begin
if(echo==0)
next_state=s1;
else
next_state=s0;
end
s1:next_state=idle; //1clk
default:next_state=idle;
endcase
end
描述状态转移
always@(posedge clk)begin
if(!rst_n)
begin
echo_cnt <=0;
echo_cnt_reg<=0;
end
else
case(cur_state)
idle:begin
echo_cnt <=0;
echo_cnt_reg<=echo_cnt_reg;
end
s0 :begin
echo_cnt<=echo_cnt+1; //计数
echo_cnt_reg<=echo_cnt_reg;
end
s1 :begin
echo_cnt <=0; //100
echo_cnt_reg<=echo_cnt; //转移数值
end
default:begin
echo_cnt <=0;
echo_cnt_reg<=0;
end
endcase
end
assign dis=(echo_cnt_reg*20)/1000/58; //厘米
assign beep=(dis>0 && dis<100)?1:0; ///1M
endmodule