1.超声波测距模块HC_SR04
HC-SR04是一种基于超声波的测距模块。该模块向前15度内发送超声波并接收回响,通过发出超声波到收到回响的这个时间间隔计算前方的障碍物距离,可以用来给智能小车做障碍物监测。可提供2cm- 400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超声波发射器、接收器与控制电路。
该模块引脚图如下:
从上图我们可以看到超声波模块的4个引脚,它们的作用罗列如下:
1.VCC: 电源引脚,超声波模块工作电压为3-5.5伏。
2.Trig: 是Trigger(触发)这个单词的缩写,该引脚用于触发超声波脉冲。
3.Echo: 该引脚会在高电平和低电平之间转换,当检测到障碍物时,在高电平保持的时间就表示信号发射出去并反射回来的时间。
4.GND: 接地引脚。
2.使用的开发板
3.代码
3.1超声波控制模块
module ultrasound_ctrl
(
input wire sys_clk ,//100MHz
input wire sys_rst_n ,//active low
input wire echo ,//回响信号
output reg fall_flag_r1 ,//标志信号
output reg [12:0] data_bin ,//数据
output reg trig //触发信号
);
//parameter define
parameter CNT_100MS_MAX = 24'D10_000_000;//100ms/10ns = 10*10^7
parameter CNT_10US_MAX = 10'd1000 ;//10us/10ns = 1000
//wire or reg define
reg [23:0] cnt_100ms ;
reg echo_r ;//对echo打一拍的信号
reg [21:0] cnt_echo ;//计数echo的高电平时间
wire echo_neg ;//echo信号的下降沿
reg echo_neg_r ;
reg [21:0] cnt_echo_r ;
//main code
//100ms的周期计数
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_100ms<=24'd0;
else if(cnt_100ms==CNT_100MS_MAX-1'b1)
cnt_100ms<=24'd0;
else
cnt_100ms<=cnt_100ms+1'b1;
end
//trig:触发脉冲trig周期为100ms,高电平时间为10us
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
trig<=1'b0;
else if(cnt_100ms<=CNT_10US_MAX-1'b1)
trig<=1'b1;
else
trig<=1'b0;
end
//echo_r:打一拍
assign echo_neg = (~echo) & echo_r ;// ? 1'b1 : 1'b0 ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
echo_r<=1'b0;
else
echo_r<=echo;
end
//cnt_echo:计数echo信号的高电平时间
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_echo<=22'd0;
else if(echo_r)
cnt_echo<=cnt_echo+1'b1;
else
cnt_echo<=22'd0;
end
//cnt_echo_r
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_echo_r<=22'd0;
else if(echo_neg)
cnt_echo_r<=cnt_echo;
else
cnt_echo_r<=cnt_echo_r;
end
//echo_neg_r
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
echo_neg_r<=1'b0;
else
echo_neg_r<=echo_neg;
end
//计算距离s=N*10*340_000/1000_000_000/2 mm = N*0.0017 mm = N*17/10000 ;
//data_bin
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
data_bin<=13'd0;
else if(echo_neg_r)
data_bin<=cnt_echo_r*17/10000; //--
else
data_bin<=data_bin;
end
//fall_flag_r1
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
fall_flag_r1<=1'b0;
else
fall_flag_r1<=echo_neg_r;
end
endmodule
3.2均值滤波模块
module ave_filter
(
input wire sys_clk ,//100m
input wire sys_rst_n ,//active low
input wire [12:0] data_bin ,//距离数据
input wire data_flag ,//距离标志信号
output wire [12:0] data_ave //均值滤波后的数据
);
//wire or reg define
reg [12:0] data_reg [7:0] ;//用于缓存8个数据
reg [15:0] data_add ;//加法计算
//main code
//数据缓存
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
data_reg[0]<=13'd0;
data_reg[1]<=13'd0;
data_reg[2]<=13'd0;
data_reg[3]<=13'd0;
data_reg[4]<=13'd0;
data_reg[5]<=13'd0;
data_reg[6]<=13'd0;
data_reg[7]<=13'd0;
end
else if(data_flag) begin//移位寄存
data_reg[0]<=data_bin;
data_reg[1]<=data_reg[0];
data_reg[2]<=data_reg[1];
data_reg[3]<=data_reg[2];
data_reg[4]<=data_reg[3];
data_reg[5]<=data_reg[4];
data_reg[6]<=data_reg[5];
data_reg[7]<=data_reg[6];
end
//else begin //保持
//end
end
//data_add:加法
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
data_add<=16'd0;
else
data_add<=data_reg[0]+data_reg[1]+data_reg[2]+data_reg[3]+data_reg[4]+data_reg[5]+data_reg[6]+data_reg[7];
end
//均值滤波后的数据输出
assign data_ave = data_add[15:3] ;//把低3位截断,等效于除以8
endmodule
3.3蜂鸣器、LED灯告警模块
module beep_led_alarm
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [12:0] data_ave ,//均值滤波后的距离数据
output reg beep ,//蜂鸣器
output reg led //LED
);
//parameter define
parameter CNT_1MS_MAX = 17'd100_000 ;//500Hz,2ms,1ms翻转一次 1ms/10ns = 10^5
//wire or reg define
reg [16:0] cnt_1ms ;
reg clk_500hz ;
//main code
//LED告警
//assign led = (data_ave<=13'd200) ? 1'b1 : 1'b0 ;//距离小于200mm时,LED灯点亮
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led<=1'b0;
else if(data_ave<=13'd200)
led<=1'b1;
else
led<=1'b0;
end
//蜂鸣器告警
//assign beep = (data_ave<=13'd50) ? clk_500hz : 1'b0 ;//距离小于50mm时,蜂鸣器发出di
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
beep<=1'b0;
else if(data_ave<=13'd50)
beep<=clk_500hz;
else
beep<=1'b0;
end
//1ms循环计数
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
cnt_1ms<=17'd0;
clk_500hz<=1'd0;
end
else if(cnt_1ms==CNT_1MS_MAX-1'B1) begin //0~99_999
cnt_1ms<=17'd0;
clk_500hz<=~clk_500hz;
end
else begin
cnt_1ms<=cnt_1ms+1'b1;
clk_500hz<=clk_500hz;
end
end
endmodule
3.4二进制码转为8421BCD码模块
module bin_to_bcd
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [12:0] data_ave ,//二进制
output wire [15:0] data_bcd //8421bcd码
);
//wire or reg define
reg [28:0] data_temp ;//中间变量
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
data_temp=29'd0;
else begin
data_temp={16'b0000_0000_0000_0000,data_ave};
repeat(13) begin //重复N次判断移位操作
if(data_temp[16:13]>=4'd5)//判断(大于等于5,加3)
data_temp[16:13]=data_temp[16:13]+4'd3;
if(data_temp[20:17]>=4'd5)//判断(大于等于5,加3)
data_temp[20:17]=data_temp[20:17]+4'd3;
if(data_temp[24:21]>=4'd5)//判断(大于等于5,加3)
data_temp[24:21]=data_temp[24:21]+4'd3;
if(data_temp[28:25]>=4'd5)//判断(大于等于5,加3)
data_temp[28:25]=data_temp[28:25]+4'd3;
//判断完成之后进行移位
data_temp=data_temp<<1'b1;
end
end
end
assign data_bcd = data_temp[28:13] ;//输出的8421BCD码
endmodule
3.5数码管显示模块
module nixie_display
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [15:0] data_bcd ,
output reg [3:0] nixie_cs ,//数码管的片选信号
output reg [7:0] nixie_seg //数码管的段选信号
);
//parameter define
parameter CNT_1MS_MAX = 17'd100_000 ;//51ms/10ns = 10^5
parameter _0 = 7'b0111111 ,
_1 = 7'b0000110 ,
_2 = 7'b1011011 ,
_3 = 7'b1001111 ,
_4 = 7'b1100110 ,
_5 = 7'b1101101 ,
_6 = 7'b1111101 ,
_7 = 7'b0000111 ,
_8 = 7'b1111111 ,
_9 = 7'b1101111 ;
//wire or reg define
reg [16:0] cnt_1ms ;
wire cnt_1ms_flag ;
reg [1:0] cnt_nixie ;//计数,标志第几个数码管亮
reg [3:0] data_nixie ;//标志亮的那个数码管需要显示的数
//main code
//1ms循环计数
assign cnt_1ms_flag = (cnt_1ms==CNT_1MS_MAX-1'B1) ? 1'b1 : 1'b0 ;
always @(posedge sys_clk or negedge sys_rst_n) begin //0~99_999
if(!sys_rst_n)
cnt_1ms<=17'd0;
else if(cnt_1ms_flag)
cnt_1ms<=17'd0;
else
cnt_1ms<=cnt_1ms+1'b1;
end
//cnt_nixie
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_nixie<=2'd0;
else if(cnt_1ms_flag)
cnt_nixie<=cnt_nixie+1'b1;
else
cnt_nixie<=cnt_nixie;
end
//片选信号
always @(*) begin //高电平片选
case(cnt_nixie)
2'd0: begin nixie_cs<=4'b1110; data_nixie<= data_bcd[3:0]; end
2'd1: begin nixie_cs<=4'b1101; data_nixie<= data_bcd[7:4]; end
2'd2: begin nixie_cs<=4'b1011; data_nixie<= data_bcd[11:8]; end
2'd3: begin nixie_cs<=4'b0111; data_nixie<= data_bcd[15:12]; end
default: begin nixie_cs<=4'b1111; data_nixie<= data_bcd[3:0]; end
endcase
end
//段选信号
always @(*) begin //高电平段选
case(data_nixie)
4'd0: nixie_seg<=_0;
4'd1: nixie_seg<=_1;
4'd2: nixie_seg<=_2;
4'd3: nixie_seg<=_3;
4'd4: nixie_seg<=_4;
4'd5: nixie_seg<=_5;
4'd6: nixie_seg<=_6;
4'd7: nixie_seg<=_7;
4'd8: nixie_seg<=_8;
4'd9: nixie_seg<=_9;
default:nixie_seg<=_0;
endcase
end
endmodule
3.6超声波测距顶层模块
module ultrasound_meter
(
input wire sys_clk ,//100MHz
input wire sys_rst_n ,//active low
input wire echo ,//回响信号
output wire trig ,//触发信号
output wire beep ,
output wire led ,
output wire [3:0] nixie_cs ,//数码管片选信号
output wire [7:0] nixie_seg //数码管段选信号
);
//wire or reg define
wire data_flag ;
wire [12:0] data_bin ;
wire [12:0] data_ave ;
wire [15:0] data_bcd ;
//Instantiation
//超声波模块
ultrasound_ctrl u_ultrasound_ctrl
(
. sys_clk ( sys_clk ) ,//100MHz
. sys_rst_n ( sys_rst_n ) ,//active low
. echo ( echo ) ,//回响信号
. fall_flag_r1 ( data_flag ) ,//标志信号
. data_bin ( data_bin ) ,//数据
. trig ( trig ) //触发信号
);
//均值滤波模块
ave_filter u_ave_filter
(
. sys_clk (sys_clk ) ,//100m
. sys_rst_n (sys_rst_n ) ,//active low
. data_bin (data_bin ) ,//距离数据
. data_flag (data_flag ) ,//距离标志信号
. data_ave (data_ave ) //均值滤波后的数据
);
//蜂鸣器和LED灯告警模块
beep_led_alarm u_beep_led_alarm
(
. sys_clk (sys_clk ) ,
. sys_rst_n (sys_rst_n ) ,
. data_ave (data_ave ) ,//均值滤波后的距离数据
. beep (beep ) ,//蜂鸣器
. led (led ) //LED
);
//二进制转8421BCD码模块
bin_to_bcd u_bin_to_bcd
(
. sys_clk ( sys_clk ) ,
. sys_rst_n ( sys_rst_n ) ,
. data_ave ( data_ave ) ,//二进制
. data_bcd ( data_bcd ) //8421bcd码
);
//数码管显示模块
nixie_display u_nixie_display
(
. sys_clk ( sys_clk ) ,
. sys_rst_n ( sys_rst_n ) ,
. data_bcd ( data_bcd ) ,
. nixie_cs ( nixie_cs ) ,//数码管的片选信号
. nixie_seg ( nixie_seg ) //数码管的段选信号
);
endmodule
4.仿真
4.1超声波控制模块
`timescale 1ns/1ns
module tb_ultrasound_ctrl ();
defparam ultrasound_ctrl_inst.CNT_100MS_MAX = 24'd10;
defparam ultrasound_ctrl_inst.CNT_10US_MAX = 10'd4 ;
reg sys_clk ;//100MHz
reg sys_rst_n ;//active low
reg echo ;//回响信号
wire fall_flag_r1 ;//标志信号
wire [12:0] data_bin ;//数据
wire trig ;//触发信号
initial begin
sys_clk = 1'b0;
sys_rst_n<=1'b0;
echo<=1'b0;
#30;
sys_rst_n<=1'b1;
#20;
echo<=1'b1;
#100000;//10000个时钟周期,100us
echo<=1'b0;
#100;//10个时钟周期
$stop;
end
always #5 sys_clk = ~sys_clk;//100MHz的时钟,周期是10ns
ultrasound_ctrl ultrasound_ctrl_inst
(
. sys_clk ( sys_clk ) ,//100MHz
. sys_rst_n ( sys_rst_n ) ,//active low
. echo ( echo ) ,//回响信号
. fall_flag_r1 ( fall_flag_r1 ) ,//标志信号
. data_bin ( data_bin ) ,//数据
. trig ( trig ) //触发信号
);
endmodule
4.2均值滤波模块
`timescale 1ns/1ns
module tb_ave_filter ();
reg sys_clk ;//100m
reg sys_rst_n ;//active low
reg [12:0] data_bin ;//距离数据
reg data_flag ;//距离标志信号
wire [12:0] data_ave ;//均值滤波后的数据
initial begin
sys_clk = 1'b0;
sys_rst_n<=1'b0;
data_bin<=13'd0;
data_flag<=1'b0;
#30;
sys_rst_n<=1'b1;
#50;
data_bin<=13'd2;//2
data_flag<=1'b1;
#10;
data_flag<=1'b0;
#50;
data_bin<=13'd3;//3
data_flag<=1'b1;
#10;
data_flag<=1'b0;
#50;
data_bin<=13'd4;//4
data_flag<=1'b1;
#10;
data_flag<=1'b0;
#50;
data_bin<=13'd5;//5
data_flag<=1'b1;
#10;
data_flag<=1'b0;
#50;
data_bin<=13'd6;//6
data_flag<=1'b1;
#10;
data_flag<=1'b0;
#50;
data_bin<=13'd7;//7
data_flag<=1'b1;
#10;
data_flag<=1'b0;
#50;
data_bin<=13'd8;//8
data_flag<=1'b1;
#10;
data_flag<=1'b0;
#50;
data_bin<=13'd9;//9
data_flag<=1'b1;
#10;
data_flag<=1'b0;
#50;
$stop;
end
always #5 sys_clk = ~sys_clk;//100MHz的时钟,周期是10ns
ave_filter ave_filter_inst
(
. sys_clk ( sys_clk ) ,//100m
. sys_rst_n ( sys_rst_n ) ,//active low
. data_bin ( data_bin ) ,//距离数据
. data_flag ( data_flag ) ,//距离标志信号
. data_ave ( data_ave ) //均值滤波后的数据
);
4.3蜂鸣器,LED灯报警模块
`timescale 1ns/1ns
module tb_beep_led_alarm ();
defparam beep_led_alarm.CNT_1MS_MAX = 17'd3 ;
reg sys_clk ;
reg sys_rst_n ;
reg [12:0] data_ave ;//均值滤波后的距离数据
wire beep ;//蜂鸣器
wire led ;//LED
initial begin
sys_clk = 1'b0;
sys_rst_n<=1'b0;
data_ave<=13'd0;
#30;
sys_rst_n<=1'b1;
#20;
data_ave<=13'd250;
#50;
data_ave<=13'd190;//led
#50;
data_ave<=13'd45;//beep
#600;
data_ave<=13'd300;
#100;//10个时钟周期
$stop;
end
always #5 sys_clk = ~sys_clk;//100MHz的时钟,周期是10ns
beep_led_alarm beep_led_alarm_inst
(
. sys_clk (sys_clk ) ,
. sys_rst_n (sys_rst_n ) ,
. data_ave (data_ave ) ,//均值滤波后的距离数据
. beep (beep ) ,//蜂鸣器
. led (led ) //LED
);
4.4二进制转码为8421BCD码模块
`timescale 1ns/1ns
module tb_bin_to_bcd ();
reg sys_clk ;
reg sys_rst_n ;
reg [12:0] data_ave ;//二进制
wire [15:0] data_bcd ; //8421bcd码
initial begin
sys_clk = 1'b0;
sys_rst_n<=1'b0;
data_ave<=13'd0;
#30;
sys_rst_n<=1'b1;
#20;
data_ave<=13'd4987;
#50;
data_ave<=13'd3214;
#50;
data_ave<=13'd1234;
#50;
data_ave<=13'd89;
#50;
data_ave<=13'd213;
#50;
data_ave<=13'd23;
#50;
#100;//10个时钟周期
$stop;
end
always #5 sys_clk = ~sys_clk;//100MHz的时钟,周期是10ns
bin_to_bcd bin_to_bcd_inst
(
. sys_clk (sys_clk ) ,
. sys_rst_n (sys_rst_n) ,
. data_ave (data_ave ) ,//二进制
. data_bcd (data_bcd ) //8421bcd码
);
endmodule
4.5数码显示模块
module tb_nixie_display ();
defparam nixie_display_inst.CNT_1MS_MAX=17'd3 ;
reg sys_clk ;
reg sys_rst_n ;
reg [15:0] data_bcd ;
wire [3:0] nixie_cs ;//数码管的片选信号
wire [7:0] nixie_seg ;//数码管的段选信号
initial begin
sys_clk = 1'b0;
sys_rst_n<=1'b0;
data_bcd<=16'h0000;
#30;
sys_rst_n<=1'b1;
#50;
data_bcd<=16'h1234;
#200;
data_bcd<=16'h5678;
#200
data_bcd<=16'h9012;
#200
#100;//10个时钟周期
$stop;
end
always #5 sys_clk = ~sys_clk;//100MHz的时钟,周期是10ns
nixie_display nixie_display_inst
(
. sys_clk ( sys_clk ) ,
. sys_rst_n ( sys_rst_n ) ,
. data_bcd ( data_bcd ) ,
. nixie_cs ( nixie_cs ) ,//数码管的片选信号
. nixie_seg ( nixie_seg ) //数码管的段选信号
);
endmodule
5.约束文件
set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_cs[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_cs[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_cs[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_cs[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_seg[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_seg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_seg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_seg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_seg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_seg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_seg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {nixie_seg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports beep]
set_property IOSTANDARD LVCMOS33 [get_ports echo]
set_property IOSTANDARD LVCMOS33 [get_ports led]
set_property IOSTANDARD LVCMOS33 [get_ports sys_rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports trig]
set_property PACKAGE_PIN H4 [get_ports sys_clk]
set_property PACKAGE_PIN F4 [get_ports sys_rst_n]
set_property PACKAGE_PIN P20 [get_ports beep]
set_property PACKAGE_PIN K4 [get_ports echo]
set_property PACKAGE_PIN AA21 [get_ports led]
set_property PACKAGE_PIN R14 [get_ports {nixie_cs[3]}]
set_property PACKAGE_PIN R18 [get_ports {nixie_cs[2]}]
set_property PACKAGE_PIN P17 [get_ports {nixie_seg[7]}]
set_property PACKAGE_PIN P15 [get_ports {nixie_seg[6]}]
set_property PACKAGE_PIN R16 [get_ports {nixie_seg[5]}]
set_property PACKAGE_PIN N13 [get_ports {nixie_seg[4]}]
set_property PACKAGE_PIN G3 [get_ports trig]
set_property PACKAGE_PIN T18 [get_ports {nixie_cs[1]}]
set_property PACKAGE_PIN N17 [get_ports {nixie_cs[0]}]
set_property PACKAGE_PIN N14 [get_ports {nixie_seg[3]}]
set_property PACKAGE_PIN P16 [get_ports {nixie_seg[2]}]
set_property PACKAGE_PIN R17 [get_ports {nixie_seg[1]}]
set_property PACKAGE_PIN N15 [get_ports {nixie_seg[0]}]