首先在前文已经介绍过了超声波模块的原理和使用,之前没有介绍回响脉冲的计数问题,这次简单说一下吧,每隔一秒发一次触发信号,当触发信号来了后,每隔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输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。
超声波测距模块电路图
电气参数
超声波时序图
原理介绍完毕:
贴代码:(这里的测得的数据是通过均值滤波处理后测得的回响数,然后通过乘法器和除法器进行进制转换后显示具体测得的距离)
这里的mul div进行距离转换用到了IP核)
top.v:
moduletop(clk,rst_n,dtube_cs_n,dtube_data,ultrasound_trig,ultrasound_echo ); inputclk; inputrst_n; outputultrasound_trig; output [3:0]dtube_cs_n; output [6:0]dtube_data; inputultrasound_echo; wire [15:0] echo_pulse_num; wireclk_100khz_en; wire [15:0]cnt; wire [15:0] out_num; wirepul_en; assigncnt={quotient_hund[3:0],quotient_thou[3:0],fractional_ten[3:0],quotient_ten[3:0]}; clk_100khz_enuut_clk_100khz_en( .clk(clk), .rst_n(rst_n), .clk_100khz_en(clk_100khz_en) ); chejuuut_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_4uut_seg_4( .clk(clk), .rst_n(rst_n), .dis_data(cnt), .dtube_cs_n(dtube_cs_n), .dtube_data(dtube_data) ); filteruut_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_outuut_mul_out( .clk(clk), //inputclk .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_outuut_div_out1( .clk(clk), //inputclk .rfd(), //outputrfd .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] fractionalwire [15:0]quotient_hund,fractional_hund; div_outuut_div_out2( .clk(clk), //inputclk .rfd(), //outputrfd .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] fractionalwire [15:0]quotient_ten,fractional_ten; div_outuut_div_out3( .clk(clk), //inputclk .rfd(), //outputrfd .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] fractionalendmodule
clk_100khz_en.v:
moduleclk_100khz_en(clk,rst_n,clk_100khz_en ); inputclk; inputrst_n; outputclk_100khz_en; reg [7:0] cnt; always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)begincnt<=1'b0;endelseif(cnt==8'd249)begincnt<=1'b0;endelsebegincnt<=cnt+1'b1;endendassignclk_100khz_en=(cnt==8'd249);endmodule
seg.v:
moduleseg_4(clk,rst_n,dis_data,dtube_cs_n,dtube_data ); inputclk; //时钟信号25MHzinputrst_n; //复位信号input [15:0] dis_data;//outputreg[3:0] dtube_cs_n; //段选数据位outputreg[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@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginTimeH<=1'b0; TimeL<=1'b0; TimeH1<=1'b0;TimeL1<=1'b0;endelsebeginTimeH<=dis_data[3:0]; TimeL<=dis_data[7:4]; TimeH1<=dis_data[11:8]; TimeL1<=dis_data[15:12]; endendinitialdiv_cnt=0;//赋初值为0//延时计数器模块always@ (posedgeclkornegedgerst_n) beginif(!rst_n) div_cnt<=8'd0;elseif(div_cnt==17'd80000)div_cnt<=8'd0; elsediv_cnt<=div_cnt+1'b1;end//显示当前的数据模块always@(posedgeclkornegedgerst_n) beginif(!rst_n) display_num<=4'h0;elseif(div_cnt<17'd20000)display_num<=TimeL; elseif((div_cnt>17'd20000)&(div_cnt <17'd40000)) display_num<=TimeH; elseif((div_cnt>17'd40000)&(div_cnt < 17'd60000)) display_num<=TimeL1; elsedisplay_num<=TimeH1; end//段选数据译码模块(共阴数码管) always@(*) beginif(!rst_n) dtube_data<=8'h00;elsebegincase(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;endcaseendend//位选选译模块always@(posedgeclkornegedgerst_n) beginif(!rst_n) dtube_cs_n<=4'b1111;elseif(div_cnt<=17'd20000)dtube_cs_n<=4'b1110;elseif((div_cnt>17'd20000)&(div_cnt <=17'd40000)) dtube_cs_n<=4'b1101;elseif((div_cnt>17'd40000)&(div_cnt <=17'd60000)) dtube_cs_n<=4'b1011;elsedtube_cs_n<=4'b0111;endendmodule
filter.v:
modulefilter(clk,rst_n,pul_en,pulse_num,filter_num ); inputclk; inputrst_n; inputpul_en; input [15:0]pulse_num; output [15:0]filter_num; reg[15:0]pul_buf[7:0]; always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginpul_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;endelseif(pul_en==1'b1)beginpul_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]; endendreg [15:0]sum_pul; always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsum_pul<=1'b0;endelsebeginsum_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]; endendassignfilter_num={3'b0,sum_pul[15:3]};endmodule
cheju.v:
modulecheju(clk,rst_n,clk_100khz_en,ultrasound_trig,ultrasound_echo,echo_pulse_en,echo_pulse_num ); inputclk; inputrst_n; inputclk_100khz_en; inputultrasound_echo;//回响信号outputultrasound_trig;//脉冲激励信号outputregecho_pulse_en; //超声波测距模块回响信号计数值有效信号outputreg[15:0] echo_pulse_num; //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值reg [16:0]timer_cnt; always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)begintimer_cnt<=1'b0;endelseif(clk_100khz_en==1'b1)beginif(timer_cnt<17'd99_999)begintimer_cnt<=timer_cnt+1'b1;endelsebegintimer_cnt<=1'b0;endendelsebegintimer_cnt<=timer_cnt; endendassignultrasound_trig=(timer_cnt==1'b1)?1'b1:1'b0;//每隔一秒产生一次脉冲 //超声波测距模块的回响信号echo打两拍,产生上升沿和下降沿标志位reg[1:0] ultrasound_echo_r; always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginultrasound_echo_r<=2'b00;endelsebeginultrasound_echo_r<= {ultrasound_echo_r[0],ultrasound_echo}; endendwirepos_echo=~ultrasound_echo_r[1] &ultrasound_echo_r[0]; //echo信号上升沿标志位,高电平有效一个时钟周期wireneg_echo=ultrasound_echo_r[1] &~ultrasound_echo_r[0]; //echo信号下降沿标志位,高电平有效一个时钟周期//以10us为单位对超声波测距模块回响信号高脉冲进行计数reg[15:0] echo_cnt; //回响高脉冲计数器always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginecho_cnt<=16'd0;endelseif(pos_echo==1'b1)beginecho_cnt<=16'd0; //计数清零endelseif(clk_100khz_en==1'b1 && ultrasound_echo_r[0]==1'b1)beginecho_cnt<=echo_cnt+1'b1;endend//计数脉冲数锁存always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginecho_pulse_num<=16'd0; endelseif(neg_echo==1'b1)beginecho_pulse_num<=echo_cnt; endend//计数脉冲有效使能信号锁存always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginecho_pulse_en<=1'b0;endelsebeginecho_pulse_en<=neg_echo; endendendmodule