赞
踩
HC-SR04 超声波测距模块可提供 2cm-400cm 的非接触式距离感测功能,测距精度可达高到的非接触式距离感测功能,测距精度可达高到 3mm ;模块包括超声波发射器、接收器与控制电路。
HC-SR04超声波测距模块共有四个引脚(见下图):
工作流程大概就是:
(1) IO 口TRIG 触发测距,给最少 10us 的高电平;
(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
(3)有信号返回,通过 IO 口 ECHO 输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2;
首先FPGA需要给超声波提供一个10us以上的触发信号(需要实现的),告诉超声波开始测距,超声波通过trigger口接收到信号后,就自动循环发出8个40KHz(200us)的周期电平(超声波模块实现的,不需要verilog实现)然后检测回波,如果超声波模块检测到了回波,就会通过echo输出口,输出一个回响信号,该回响会持续信号发射到接收时间长度的高电平。所以需要一个计时器来记录这段高电平持续(FPGA需要实现的,接收到echo上升沿后就开启计时,下降沿就停止)的时间长短。得到这个时间后就可以通过计算公式计算出大致的距离。
module clk_div( input wire clk, input wire rst_n, output reg clk_us ); parameter CNT_MAX = 5'd25; //1us有50个时钟周期,一半一半 reg [4:0] cnt; wire add_cnt; wire end_cnt; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt <= 0; clk_us <= 1'b0; end else if(add_cnt)begin if(end_cnt)begin clk_us <= ~clk_us;//取反 cnt <= 0; end else begin cnt <= cnt + 1'b1; end end else begin cnt <= cnt; end end assign add_cnt = 1'b1; assign end_cnt = add_cnt && cnt == CNT_MAX - 1; endmodule
//发送15us的触发信号给hc_sr module hc_sr_trig ( input wire clk_us, input wire rst_n, output wire trig_out ); //接收一次信号最长间隔时间是: //发送8个40KHz是200us。 //最长距离是400cm,来回时长为24ms左右 //设定间隔为30ms发送一次trig //则需要时钟1MHz个数30_000 parameter MAX_CNT = 15'd30_000; //定义一个计数器 reg [14:0] cnt; wire add_cnt; wire end_cnt; always @(posedge clk_us or negedge rst_n)begin if(!rst_n)begin cnt <= 0; end else if(add_cnt)begin if(end_cnt)begin cnt <= 0; end else begin cnt <= cnt + 1'b1; end end else begin cnt <= cnt; end end assign add_cnt = 1'b1; assign end_cnt = add_cnt && cnt == MAX_CNT - 1; assign trig_out = cnt <15 ? 1'b1 : 1'b0;//发送15us的高电平 endmodule
//接收hc_sr的echo信号,并解析数据 module hc_sr_echo ( input wire clk , input wire clk_us , input wire rst_n , input wire echo , output reg [24:0] data_out //距离单位为cm,乘以1000的值 ); //echo最多测量400cm parameter MAX_ECHO = 15'd25_000; //检测下降沿 reg r1_echo, r2_echo; wire echo_pos, echo_neg; reg [14:0] cnt ; wire add_cnt; wire end_cnt; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin r1_echo <= 0; r2_echo <= 0; end //打拍,延时一个时钟周期 else begin r1_echo <= echo; r2_echo <= r1_echo; end end //如果r2_echo为1,并且r1_echo为0,则此时为下降沿 assign echo_neg = r2_echo & ~r1_echo; //如果r1_echo为1,并且r2_echo为0,则此时为上升沿 assign echo_pos = ~r2_echo & r1_echo; //当echo为1时开始计数 always @(posedge clk_us or negedge rst_n)begin if(!rst_n)begin cnt <= 0; end else if(add_cnt)begin if(end_cnt)begin cnt <= cnt;//如果没有检测到障碍物,cnt就保持 end else begin cnt <= cnt + 1'b1; end end else begin cnt <= 0; end end assign add_cnt = echo; assign end_cnt = add_cnt && cnt == MAX_ECHO - 1; //当检测到下降沿的时候,就开始计算距离 //cnt最高计数为25_000us,换算成距离,t=cnt * 10^(-3)*34/2(cm) //最大数值为t = cnt*17/1000 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin data_out <= 0; end else if(echo_neg)begin data_out <= (cnt << 4) + cnt;//cnt*17 end else begin data_out <= data_out; end end endmodule
module hc_sr_driver ( input wire clk, input wire rst_n, input wire echo, output wire trig_out, output wire [24:0] data_out//实际距离还需要除以1000 ); wire clk_us; clk_div clk_div_inst ( .clk (clk) , .rst_n (rst_n) , .clk_us (clk_us) ); hc_sr_trig hc_sr_trig_inst ( .clk_us (clk_us) , .rst_n (rst_n) , .trig_out (trig_out) ); hc_sr_echo hc_sr_echo_inst ( .clk (clk) , .clk_us (clk_us) , .rst_n (rst_n) , .echo (echo) , .data_out (data_out)//距离单位cm乘以1000的值 ); endmodule
DE115的数码管和之前使用的板子不同,数码管不再是片选和段选选中,DE115上的是分开的,所以需要考虑8个单独的数码管。代码如下:
module sel_driver( input wire Clk , input wire Rst_n , input wire [24:0] data_o , output wire [6:0] hex1 , output wire [6:0] hex2 , output wire [6:0] hex3 , output wire [6:0] hex4 , output wire [6:0] hex5 , output wire [6:0] hex6 , output wire [6:0] hex7 , output wire [6:0] hex8 ); parameter NOTION = 4'd10, FUSHU = 4'd11; parameter MAX20us = 10'd1000; reg [9:0] cnt_20us; reg [7:0] sel_r; reg [3:0] number; reg [6:0] seg_r; reg [6:0] hex1_r; reg [6:0] hex2_r; reg [6:0] hex3_r; reg [6:0] hex4_r; reg [6:0] hex5_r; reg [6:0] hex6_r; reg [6:0] hex7_r; reg [6:0] hex8_r; //20微妙计数器 always @(posedge Clk or negedge Rst_n) begin if (!Rst_n) begin cnt_20us <= 10'd0; end else if (cnt_20us == MAX20us - 1'd1) begin cnt_20us <= 10'd0; end else begin cnt_20us <= cnt_20us + 1'd1; end end //单个信号sel_r位拼接约束 always @(posedge Clk or negedge Rst_n) begin if (!Rst_n) begin sel_r <= 8'b11_11_11_10; end else if (cnt_20us == MAX20us - 1'd1) begin sel_r <= {sel_r[6:0],sel_r[7]}; end else begin sel_r <= sel_r; end end /*拿到数字*/ always @(*) begin case (sel_r) 8'b11_11_11_10: number = data_o/100_000 ;//百位 8'b11_11_11_01: number = (data_o%100_000)/10_000 ;//十位 8'b11_11_10_11: number = (data_o%10_000)/1_000 ;//个位cm 8'b11_11_01_11: number = FUSHU ;//表示小数点 8'b11_10_11_11: number = (data_o%1_000)/1_00 ; 8'b11_01_11_11: number = (data_o%1_00)/1_0 ; 8'b10_11_11_11: number = data_o%10 ; default: number = 4'd0 ; endcase end /*通过数字解析出seg值*/ always @(*) begin case (number) 4'd0 : seg_r = 7'b100_0000; 4'd1 : seg_r = 7'b111_1001; 4'd2 : seg_r = 7'b010_0100; 4'd3 : seg_r = 7'b011_0000; 4'd4 : seg_r = 7'b001_1001; 4'd5 : seg_r = 7'b001_0010; 4'd6 : seg_r = 7'b000_0010; 4'd7 : seg_r = 7'b111_1000; 4'd8 : seg_r = 7'b000_0000; 4'd9 : seg_r = 7'b001_0000; NOTION : seg_r = 7'b111_1111; FUSHU : seg_r = 7'b011_1111; default : seg_r = 7'b111_1111; endcase end always @(*) begin case (sel_r) 8'b11_11_11_10: hex1_r = seg_r; 8'b11_11_11_01: hex2_r = seg_r; 8'b11_11_10_11: hex3_r = seg_r; 8'b11_11_01_11: hex4_r = seg_r; 8'b11_10_11_11: hex5_r = seg_r; 8'b11_01_11_11: hex6_r = seg_r; 8'b10_11_11_11: hex7_r = seg_r; 8'b01_11_11_11: hex8_r = seg_r; default: seg_r = seg_r; endcase end assign hex1 = hex1_r; assign hex2 = hex2_r; assign hex3 = hex3_r; assign hex4 = hex4_r; assign hex5 = hex5_r; assign hex6 = hex6_r; assign hex7 = hex7_r; assign hex8 = hex8_r; endmodule
module top ( input wire clk , input wire rst_n , input wire echo , output wire trig_out, output wire [6:0] hex1 , output wire [6:0] hex2 , output wire [6:0] hex3 , output wire [6:0] hex4 , output wire [6:0] hex5 , output wire [6:0] hex6 , output wire [6:0] hex7 , output wire [6:0] hex8 , output wire beep , output wire [3:0] led ); wire [24:0] data_out; hc_sr_driver hc_sr_driver_inst( .clk (clk), .rst_n (rst_n), .echo (echo), .trig_out (trig_out), .data_out (data_out) ); sel_driver sel_driver_inst( .Clk (clk ), .Rst_n (rst_n ), .data_o (data_out ), .hex1 (hex1), .hex2 (hex2), .hex3 (hex3), .hex4 (hex4), .hex5 (hex5), .hex6 (hex6), .hex7 (hex7), .hex8 (hex8) ); endmodule
package require ::quartus::project set_location_assignment PIN_Y2 -to clk set_location_assignment PIN_M23 -to rst_n set_location_assignment PIN_AC15 -to echo set_location_assignment PIN_AB22 -to trig_out set_location_assignment PIN_AA14 -to hex1[6] set_location_assignment PIN_AG18 -to hex1[5] set_location_assignment PIN_AF17 -to hex1[4] set_location_assignment PIN_AH17 -to hex1[3] set_location_assignment PIN_AG17 -to hex1[2] set_location_assignment PIN_AE17 -to hex1[1] set_location_assignment PIN_AD17 -to hex1[0] set_location_assignment PIN_AC17 -to hex2[6] set_location_assignment PIN_AA15 -to hex2[5] set_location_assignment PIN_AB15 -to hex2[4] set_location_assignment PIN_AB17 -to hex2[3] set_location_assignment PIN_AA16 -to hex2[2] set_location_assignment PIN_AB16 -to hex2[1] set_location_assignment PIN_AA17 -to hex2[0] set_location_assignment PIN_AH18 -to hex3[6] set_location_assignment PIN_AF18 -to hex3[5] set_location_assignment PIN_AG19 -to hex3[4] set_location_assignment PIN_AH19 -to hex3[3] set_location_assignment PIN_AB18 -to hex3[2] set_location_assignment PIN_AC18 -to hex3[1] set_location_assignment PIN_AD18 -to hex3[0] set_location_assignment PIN_AE18 -to hex4[6] set_location_assignment PIN_AF19 -to hex4[5] set_location_assignment PIN_AE19 -to hex4[4] set_location_assignment PIN_AH21 -to hex4[3] set_location_assignment PIN_AG21 -to hex4[2] set_location_assignment PIN_AA19 -to hex4[1] set_location_assignment PIN_AB19 -to hex4[0] set_location_assignment PIN_Y19 -to hex5[6] set_location_assignment PIN_AF23 -to hex5[5] set_location_assignment PIN_AD24 -to hex5[4] set_location_assignment PIN_AA21 -to hex5[3] set_location_assignment PIN_AB20 -to hex5[2] set_location_assignment PIN_U21 -to hex5[1] set_location_assignment PIN_V21 -to hex5[0] set_location_assignment PIN_W28 -to hex6[6] set_location_assignment PIN_W27 -to hex6[5] set_location_assignment PIN_Y26 -to hex6[4] set_location_assignment PIN_W26 -to hex6[3] set_location_assignment PIN_Y25 -to hex6[2] set_location_assignment PIN_AA26 -to hex6[1] set_location_assignment PIN_AA25 -to hex6[0] set_location_assignment PIN_U24 -to hex7[6] set_location_assignment PIN_U23 -to hex7[5] set_location_assignment PIN_W25 -to hex7[4] set_location_assignment PIN_W22 -to hex7[3] set_location_assignment PIN_W21 -to hex7[2] set_location_assignment PIN_Y22 -to hex7[1] set_location_assignment PIN_M24 -to hex7[0] set_location_assignment PIN_H22 -to hex8[6] set_location_assignment PIN_J22 -to hex8[5] set_location_assignment PIN_L25 -to hex8[4] set_location_assignment PIN_L26 -to hex8[3] set_location_assignment PIN_E17 -to hex8[2] set_location_assignment PIN_F22 -to hex8[1] set_location_assignment PIN_G18 -to hex8[0]
从实验结果观察发现测量距离同实际还是具有一定的误差,可能是由传感器本身的噪声、回波的多路径传播、环境的干扰等原因造成。
HC-SR04超声波测距模块的原理
基于DE2 115开发板驱动HC_SR04超声波测距模块【附源码】
【嵌入式系统应用开发】FPGA——基于HC-SR04超声波测距
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。