首先在前文已经介绍过了超声波模块的原理和使用,之前没有介绍回响脉冲的计数问题,这次简单说一下吧,每隔一秒发一次触发信号,当触发信号来了后,每隔10Us进行一次脉冲的计数,计算出每秒的脉冲数,这时候就有一个问题,怎么根据回响信号进行计数呢?
1、首先我们可以看到回响信号是根据距离成正比的,而且脉冲计数是每隔10us进行一次脉冲方便进行距离的计算(精度2mm 决定)
2、当本次回响脉冲开始时候可以进行上次的数据的清零,然后进行本次数据的计数,当回响信号结束数据计数终止,将本次的计数值输出,用于距离的测量。
3、计算公式:
如果 距离是m 时间取s: s=346*t/2;
如果距离是mm 时间取10us: s*0.001=346*t*0.00001/2 即:s=1.73/t 方便计算则取 s=(443 X t )/256
C-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能, 测距精度可达高到3mm;模块包括超声波发射器、接收器与控制电路。基本工作原理:
(1)采用IO口TRIG触发测距,给至少10us的高电平信号;
(2)模块自动发送8个40khz的方波,自动检测是否有信号返回;
(3)有信号返回,通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。
超声波测距模块电路图
电气参数
1
超声波时序图
原理介绍完毕:
贴代码:(这里的测得的数据是通过均值滤波处理后测得的回响数,然后通过乘法器和除法器进行进制转换后显示具体测得的距离)
这里的mul div进行距离转换用到了IP核)
top.v:
module top(clk,rst_n,dtube_cs_n,dtube_data,ultrasound_trig,ultrasound_echo
);
input clk;
input rst_n;
output ultrasound_trig;
output [3:0]dtube_cs_n;
output [6:0]dtube_data;
input ultrasound_echo;
wire [15:0] echo_pulse_num;
wire clk_100khz_en;
wire [15:0]cnt;
wire [15:0] out_num;
wire pul_en;
assign cnt={quotient_hund[3:0],quotient_thou[3:0],fractional_ten[3:0],quotient_ten[3:0]};
clk_100khz_en uut_clk_100khz_en(
.clk(clk),
.rst_n(rst_n),
.clk_100khz_en(clk_100khz_en)
);
cheju uut_cheju(
.clk(clk),
.rst_n(rst_n),
.clk_100khz_en(clk_100khz_en),
.ultrasound_trig(ultrasound_trig),
.ultrasound_echo(ultrasound_echo),
.echo_pulse_en(pul_en),
.echo_pulse_num(echo_pulse_num)
);
seg_4 uut_seg_4(
.clk(clk),
.rst_n(rst_n),
.dis_data(cnt),
.dtube_cs_n(dtube_cs_n),
.dtube_data(dtube_data)
);
filter uut_filter(
.clk(clk),
.rst_n(rst_n),
.pul_en(pul_en),
.pulse_num(echo_pulse_num),
.filter_num(out_num)
);
//距离换算
wire[31:0]mul_dout;
mul_out uut_mul_out(
.clk(clk), // input clk
.a(16'd443), // input [15 : 0] a
.b(out_num), // input [15 : 0] b
.p(mul_dout) // output [31 : 0] p
);
//利用除法器进行进制转换
wire [15:0]quotient_thou,fractional_thou;
div_out uut_div_out1(
.clk(clk), // input clk
.rfd(), // output rfd
.dividend(mul_dout[23:8]), // input [15 : 0] dividend
.divisor(16'd1000), // input [15 : 0] divisor
.quotient(quotient_thou), // output [15 : 0] quotient
.fractional(fractional_thou)
); // output [15 : 0] fractional
wire [15:0]quotient_hund,fractional_hund;
div_out uut_div_out2(
.clk(clk), // input clk
.rfd(), // output rfd
.dividend(fractional_thou), // input [15 : 0] dividend
.divisor(16'd100), // input [15 : 0] divisor
.quotient(quotient_hund), // output [15 : 0] quotient
.fractional(fractional_hund)
); // output [15 : 0] fractional
wire [15:0]quotient_ten,fractional_ten;
div_out uut_div_out3(
.clk(clk), // input clk
.rfd(), // output rfd
.dividend(fractional_hund), // input [15 : 0] dividend
.divisor(16'd10), // input [15 : 0] divisor
.quotient(quotient_ten), // output [15 : 0] quotient
.fractional(fractional_ten)
); // output [15 : 0] fractional
endmodule
clk_100khz_en.v:
module clk_100khz_en(clk,rst_n,clk_100khz_en
);
input clk;
input rst_n;
output clk_100khz_en;
reg [7:0] cnt;
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt<=1'b0;
end
else if(cnt==8'd249)begin
cnt<=1'b0;
end
else begin
cnt<=cnt+1'b1;
end
end
assign clk_100khz_en=(cnt==8'd249);
endmodule
seg.v:
module seg_4(clk,rst_n,dis_data,dtube_cs_n,dtube_data
);
input clk; //时钟信号25MHz
input rst_n; //复位信号
input [15:0] dis_data;//
output reg[3:0] dtube_cs_n; //段选数据位
output reg[6:0] dtube_data;//位选数据位
reg [3:0]TimeH; //两位输入高位 [0]
reg [3:0]TimeL; //两位输入低位 [1]
reg [3:0]TimeH1; //两位输入高位 [2]
reg [3:0]TimeL1; //两位输入低位 [3]
reg [3:0] display_num; //当前显示数据
reg [16:0] div_cnt; //延时计数器计数位
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
TimeH<=1'b0;
TimeL<=1'b0;
TimeH1<=1'b0;
TimeL1<=1'b0;
end
else begin
TimeH <=dis_data[3:0];
TimeL <=dis_data[7:4];
TimeH1<=dis_data[11:8];
TimeL1<=dis_data[15:12];
end
end
initial div_cnt = 0;//赋初值为0
//延时计数器模块
always@ (posedge clk or negedge rst_n)
begin
if(!rst_n)
div_cnt <= 8'd0;
else if(div_cnt==17'd80000)
div_cnt <= 8'd0;
else
div_cnt <= div_cnt+1'b1;
end
//显示当前的数据模块
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
display_num <= 4'h0;
else if(div_cnt < 17'd20000)
display_num <= TimeL;
else if((div_cnt>17'd20000)&(div_cnt <17'd40000))
display_num <= TimeH;
else if((div_cnt>17'd40000)&(div_cnt < 17'd60000))
display_num <=TimeL1;
else
display_num <=TimeH1;
end
//段选数据译码模块(共阴数码管)
always @(*)
begin
if(!rst_n)
dtube_data <= 8'h00;
else begin
case(display_num)
4'h0: dtube_data <= 8'h3f;
4'h1: dtube_data <= 8'h06;
4'h2: dtube_data <= 8'h5b;
4'h3: dtube_data <= 8'h4f;
4'h4: dtube_data <= 8'h66;
4'h5: dtube_data <= 8'h6d;
4'h6: dtube_data <= 8'h7d;
4'h7: dtube_data <= 8'h07;
4'h8: dtube_data <= 8'h7f;
4'h9: dtube_data <= 8'h6f;
default:dtube_data <= 8'h00;
endcase
end
end
//位选选译模块
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
dtube_cs_n <= 4'b1111;
else if(div_cnt <= 17'd20000)
dtube_cs_n <= 4'b1110;
else if((div_cnt>17'd20000)&(div_cnt <=17'd40000))
dtube_cs_n <= 4'b1101;
else if((div_cnt>17'd40000)&(div_cnt <=17'd60000))
dtube_cs_n <= 4'b1011;
else
dtube_cs_n <=4'b0111;
end
endmodule
filter.v:
module filter(clk,rst_n,pul_en,pulse_num,filter_num
);
input clk;
input rst_n;
input pul_en;
input [15:0]pulse_num;
output [15:0]filter_num;
reg[15:0]pul_buf[7:0];
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
pul_buf[0]<=1'b0;
pul_buf[1]<=1'b0;
pul_buf[2]<=1'b0;
pul_buf[3]<=1'b0;
pul_buf[4]<=1'b0;
pul_buf[5]<=1'b0;
pul_buf[6]<=1'b0;
pul_buf[7]<=1'b0;
end
else if(pul_en==1'b1)begin
pul_buf[0]<=pulse_num;
pul_buf[1]<=pul_buf[0];
pul_buf[2]<=pul_buf[1];
pul_buf[3]<=pul_buf[2];
pul_buf[4]<=pul_buf[3];
pul_buf[5]<=pul_buf[4];
pul_buf[6]<=pul_buf[5];
pul_buf[7]<=pul_buf[6];
end
end
reg [15:0]sum_pul;
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sum_pul<=1'b0;
end
else begin
sum_pul<=pul_buf[0]+pul_buf[1]+pul_buf[2]+pul_buf[3]+pul_buf[4]+pul_buf[5]+pul_buf[6]+pul_buf[7];
end
end
assign filter_num ={3'b0,sum_pul[15:3]};
endmodule
cheju.v:
module cheju(clk,rst_n,clk_100khz_en,ultrasound_trig,ultrasound_echo,echo_pulse_en,echo_pulse_num
);
input clk;
input rst_n;
input clk_100khz_en;
input ultrasound_echo;//回响信号
output ultrasound_trig;//脉冲激励信号
output reg echo_pulse_en; //超声波测距模块回响信号计数值有效信号
output reg[15:0] echo_pulse_num; //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值
reg [16:0]timer_cnt;
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
timer_cnt<=1'b0;
end
else if(clk_100khz_en==1'b1)begin
if(timer_cnt<17'd99_999)begin
timer_cnt<=timer_cnt+1'b1;
end
else begin
timer_cnt<=1'b0;
end
end
else begin
timer_cnt<=timer_cnt;
end
end
assign ultrasound_trig=(timer_cnt==1'b1)?1'b1:1'b0;//每隔一秒产生一次脉冲
//超声波测距模块的回响信号echo打两拍,产生上升沿和下降沿标志位
reg[1:0] ultrasound_echo_r;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
ultrasound_echo_r <= 2'b00;
end
else begin
ultrasound_echo_r <= {ultrasound_echo_r[0],ultrasound_echo};
end
end
wire pos_echo = ~ultrasound_echo_r[1] & ultrasound_echo_r[0]; //echo信号上升沿标志位,高电平有效一个时钟周期
wire neg_echo = ultrasound_echo_r[1] & ~ultrasound_echo_r[0]; //echo信号下降沿标志位,高电平有效一个时钟周期
//以10us为单位对超声波测距模块回响信号高脉冲进行计数
reg[15:0] echo_cnt; //回响高脉冲计数器
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
echo_cnt <= 16'd0;
end
else if(pos_echo==1'b1)begin
echo_cnt <= 16'd0; //计数清零
end
else if(clk_100khz_en==1'b1 && ultrasound_echo_r[0]==1'b1)begin
echo_cnt <= echo_cnt+1'b1;
end
end
//计数脉冲数锁存
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
echo_pulse_num <= 16'd0;
end
else if(neg_echo==1'b1)begin
echo_pulse_num <= echo_cnt;
end
end
//计数脉冲有效使能信号锁存
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
echo_pulse_en <= 1'b0;
end
else begin
echo_pulse_en <= neg_echo;
end
end
endmodule