实验五 危险距离报警器实验报告
目录
实验目的
利用NEXYS A7及verilog代码制作危险距离报警器,借助pmod模块MaxSonar实现测距功能。应用场景包括:倒车入库刮蹭警示、汽车盲区检测防误伤、极端天气水位警报等。
实验内容
原理描述
1. 流水灯实现
- 通过计数器
cnt
和led_control
,实现0.2s为周期的循环流水灯。每到一个周期,流水灯向下移动一位,用case语句实现不同LED的点亮。 - 舍弃reset端,确保流水灯通电后自动循环。
2. 三色灯原理
- Nexys A7三色LED每种颜色高电平点亮,紫色由红蓝同时高电平实现。
- 本实验让三色灯在距离小于10英寸时闪烁(紫色),用计数器
count_1
调节闪烁频率。 - 通过判断距离的BCD码(two0&&three0)来判定是否小于10英寸。
3. CLOSE显示
- reset为0时,调用close模块显示“CLOSE”,reset为1时进行测距。
- close模块通过数码管动态扫描显示CLOSE。
4. Pmod MaxSonar测距模块
- 超声波测距,有效范围6255英寸(15648cm),1英寸分辨率。
- 输出方式:UART、模拟、PWM。实验采用PWM测脉冲宽度,1英寸对应147us高电平。
- 每49ms输出一次测距结果。
- 与FPGA连接后,Verilog检测高电平时间,计算距离,并显示在数码管上。
Verilog HDL设计源代码
input clk,
input reset,//控制信号,控制选择工作模式还是关闭模式
input ultra_sound_signal, //接受超声波的信号
output reg rx,//与MaxSonar的RX端口连接
output reg [6:0] sseg,//控制每段LED的亮灭
output reg [7:0] an,//控制哪一个八位数码管工作
output reg [15:0]led,//控制流水灯
output reg [1:0]color_1,//控制第一个三色灯
output reg [1:0]color_2//控制第二个三色灯
);
reg [23:0] time_; // 反射波的传播时间,23bits足够存储
wire[3:0]one,two,three; //所测量的英寸数的个位、十位、百位
reg [32:0]count;//计clk的周期,每加一就计一个周期
reg [7:0]distance; //所测的距离
wire [7:0]an_distance;//由子模块scan_seg_disp传入的,用于控制哪一个八位数码管工作
wire [6:0]sseg_distance;//由子模块scan_seg_disp传入的,用于控制每段LED的亮灭
wire [7:0]an_close;//由子模块close传入的,用于控制哪一个八位数码管工作
wire [6:0]sseg_close;//由子模块close传入的,用于控制每段LED的亮灭
///用于得到distance的代码块///
always@(posedge clk,negedge reset)
begin
if(!reset)
begin
rx <= 0;
end
else if(time_ >= 0 &&time_ <=2000)
begin
rx <= 1;
time_ <= time_ + 1;
end
else if(time_ == 4900000)
begin
distance <= count *255 / 3750000;
time_ <= time_ + 1;
end
else if(time_ == 5000000)
begin
time_ <= 0;
end
else
begin
time_ <= time_ + 1;
rx <= 0;
end
end
always@(posedge clk)
begin
if(time_ >=2000 && time_ <= 3850000 && ultra_sound_signal == 1)
count <= count + 1;
if(time_ == 4900000)
count <= 0;
end
///选择使用close还是scan_seg_disp传入的控制数码管的信号///
always@(posedge clk)
begin
if(reset==1'b0)
begin
an<=an_close;
sseg<=sseg_close;
end
else if(reset==1'b1)
begin
an<=an_distance;
sseg<=sseg_distance;
end
end
实现流水灯的代码块
reg [23:0] cnt;
always@(posedge clk )
begin
if(cnt<24'd999_9999)
cnt<=cnt+1'b1;
else
cnt<=0;
end
reg [4:0] led_control;
//状态切换和状态赋值
always@(posedge clk)
begin
if(cnt==24'd999_9999)
led_control<=led_control+1'b1;
else
led_control<=led_control;
end
always@(posedge clk)
begin
case(led_control)
5'b00000:led<=16'b1000000000000000;
5'b00001:led<=16'b0100000000000000;
5'b00010:led<=16'b0010000000000000;
5'b00011:led<=16'b0001000000000000;
5'b00100:led<=16'b0000100000000000;
5'b00101:led<=16'b0000010000000000;
5'b00110:led<=16'b0000001000000000;
5'b00111:led<=16'b0000000100000000;
5'b01000:led<=16'b0000000010000000;
5'b01001:led<=16'b0000000001000000;
5'b01010:led<=16'b0000000000100000;
5'b01011:led<=16'b0000000000010000;
5'b01100:led<=16'b0000000000001000;
5'b01101:led<=16'b0000000000000100;
5'b01110:led<=16'b0000000000000010;
5'b01111:led<=16'b0000000000000001;
5'b10000:led<=16'b0000000000000001;
5'b10001:led<=16'b0000000000000010;
5'b10010:led<=16'b0000000000000100;
5'b10011:led<=16'b0000000000001000;
5'b10100:led<=16'b0000000000010000;
5'b10101:led<=16'b0000000000100000;
5'b10110:led<=16'b0000000001000000;
5'b10111:led<=16'b0000000010000000;
5'b11000:led<=16'b0000000100000000;
5'b11001:led<=16'b0000001000000000;
5'b11010:led<=16'b0000010000000000;
5'b11011:led<=16'b0000100000000000;
5'b11100:led<=16'b0001000000000000;
5'b11101:led<=16'b0010000000000000;
5'b11110:led<=16'b0100000000000000;
5'b11111:led<=16'b1000000000000000;
endcase
end
//用于实现三色灯的代码块/
reg [23:0]count_1;
always@(posedge clk)
begin
if(count_1<24'd10000001)
count_1<=count_1+1;
else if(count_1==24'd10000001)
count_1<=1'b0;
end
always@(posedge clk)
begin
if(count_1<24'd10000000&&count_1>24'd6000000&&two==3'd0&&three==3'd0&&reset==1'b1)
begin
color_1<=2'b11;
color_2<=2'b11;
end
else
begin
color_1<=2'b00;
color_2<=2'b00;
end
end
//三个子模块的实例化/
bintobcd8 bintobcd_1(
.clk(clk),
.rst(reset),
.bin(distance),
.one(one),
.ten(two),
.hun(three)
);
scan_seg_disp scan_seg_disp_1(
.clk(clk),
.rst(reset),
.one(one),
.ten(two),
.hun(three),
.an_d(an_distance),
.sseg_d(sseg_distance)
);
close close1(
.clk(clk),
.sseg_c(sseg_close),
.an_c(an_close)
);
endmodule
///将二进制表示的distance转化为十进制数(左移加三法)///
module bintobcd8(
input clk, rst,
input [7:0] bin,
output reg [3:0]one,ten,hun);
reg [17:0] shift_reg;
reg [3:0] count;//这里count是用来表示移位次数的
always@(posedge clk, negedge rst)
if(!rst) begin//复位
one=0;
ten=0;
hun=0;
shift_reg=0;
count=0;
end
else begin
if (count == 0)
shift_reg = {10'd0, bin};
if (count < 4'd8) begin
count = count+1;
if (shift_reg[11:8]>4)//[11:8]与[15:12]是移位的8位
shift_reg[11:8]= shift_reg[11:8]+2'b11;
if (shift_reg[15:12]>4)
shift_reg[15:12] = shift_reg[15:12]+2'b11;
shift_reg[17:1] = shift_reg[16:0];
end
else if (count==4'd8) begin
one= shift_reg[11:8];
ten = shift_reg[15:12];
hun= {2'b00,shift_reg[17:16]};
count = count+1;
end
else
count = count-9;
end
endmodule
///将得到的距离的BCD码转换为数码管显示
module scan_seg_disp (
input clk, rst,
input [3:0] one, ten, hun,
output reg [7:0] an_d,//控制8位数码管
output reg [6:0] sseg_d//控制8位数码管的每一段,这里不包含小数
);
localparam N=20;
reg [N-1:0] cnt;
reg [3:0] hex;
always @(posedge clk , negedge rst)//敏感列表里应该与计数器里的保持一致,这样才能同时激活运行
begin
if(!rst) begin//复位
cnt = 0;
hex = 4'd10;
end
else begin//分频
cnt = cnt + 1;
case (cnt[N-1:N-2])
2'b00:begin
hex = one;
an_d = 8'b11111110;
end
2'b01:begin
hex = ten;
an_d = 8'b11111101;
end
2'b11:begin
hex = hun;
an_d = 8'b11111011;
end
endcase
end
end
always@ (*)
case(hex)当相应的管脚为低电平0时,点亮该段Led。
4'h0:sseg_d[6:0] = 7'b0000001;
4'h1:sseg_d[6:0] = 7'b1001111;
4'h2:sseg_d[6:0] = 7'b0010010;
4'h3:sseg_d[6:0] = 7'b0000110;
4'h4:sseg_d[6:0] = 7'b1001100;
4'h5:sseg_d[6:0] = 7'b0100100;
4'h6:sseg_d[6:0] = 7'b0100000;
4'h7:sseg_d[6:0] = 7'b0001111;
4'h8:sseg_d[6:0] = 7'b0000000;
4'h9:sseg_d[6:0] = 7'b0000100;
default:
sseg_d[6:0] = 7'b1111111;
endcase
endmodule
///当reset置为0时,用于显示close的模块//
module close(
input clk,
output [6:0]sseg_c,
output [7:0]an_c
);
wire [25:0]slow_clk;
//模块的实例化,close模块的功能由这两个子模块承担
slow_clk slow_clk1(
.clk(clk),
.slow_clk(slow_clk)
);
LED LED1(
.clk(clk),
.slow_clk(slow_clk),
.control(sseg_c),
.an_LED(an_c)
);
endmodule
/close模块让数码管显示的功能由此模块承担/
module LED(
input clk,
input [25:0]slow_clk,
output reg [6:0]control,
output reg [7:0]an_LED
);
wire [6:0]controlE=7'b0110000;
wire [6:0]controlS=7'b0100100;
wire [6:0]controlO=7'b0000001;
wire [6:0]controlL=7'b1110001;
wire [6:0]controlC=7'b0110001;
always@(posedge clk)//控制三段数码管的亮灭,使人眼看到的三段数码管常亮
begin
if(slow_clk[19:17]==3'b000)
begin
an_LED<=8'b11111110;
control<=controlE;
end
else if(slow_clk[19:17]==3'b010)
begin
an_LED<=8'b11111101;
control<=controlS;
end
else if(slow_clk[19:17]==3'b100)
begin
an_LED<=8'b11111011;
control<=controlO;
end
else if(slow_clk[19:17]==3'b110)
begin
an_LED<=8'b11110111;
control<=controlL;
end
else if(slow_clk[19:17]==3'b111)
begin
an_LED<=8'b11101111;
control<=controlC;
end
end
endmodule
//close模块的分频工作由这个模块承担
module slow_clk(//分频
input clk,
output reg [25:0]slow_clk
);
always@(posedge clk)
slow_clk<=slow_clk+1;
endmodule
XDC文件配置
(4)下板测试
Ps:流水灯不便使用单张照片演示,以下图片的拍摄过程中流水灯在一直运行,作装饰用。
①当reset(v10端口)置为0时,不工作,显示CLOSE
②当reset(v10端口)置为1时,开始工作,显示距离,单位为英寸
③当reset(v10端口)置为1时,开始工作,显示距离,且当距离小于10英寸时三色灯闪烁(紫光)
3.实验体会
①.通过对pmod模块MaxSonar的使用,我们更深刻的理解了FPGA的可扩展性——通过连接不同的pmod模块可以实现各种各样的功能。
②.搞清楚硬件的工作原理是重中之重,最初我们认为MaxSonar与老式的测距仪器相同——即发送超声波与接受超声波,之后经过查资料发现它的原理与老式的不同。经过这次教训,后来我们便更注重硬件的工作原理,少走了很多弯路。
③.经过这次实验,我们对verilog语言的认识更进了一步,解决了实验过程中很多的代码问题,诸如并行驱动问题、数据截断问题、模块调用问题,等等。
④.硬件的使用应与现实生活紧密结合起来,最好可以提供一些解决现实问题的思路,将硬件功能与硬件应用结合起来,例如本实验的硬件实现的功能便是测距,在此基础上,结合现实问题,我们联想到了这个功能可能用于水位检测,车辆盲区检测等场景。
⑤.两个人的实验我们合理分工,各自攻坚,遇到问题时共同思考交流学习,认识到团队协作的重要性。
⑥.学会查找资料并耐心阅读,有很多外文的,需要我们运用翻译工具,之前一直不知道WPS里PDF可以划词翻译,发现以后效率提高了不少。