大实验:基于赛灵思csg324100T,pmodMAXsonar的危险距离警报

发布于:2025-06-09 ⋅ 阅读:(22) ⋅ 点赞:(0)

实验五 危险距离报警器实验报告

目录

  1. 实验目的
  2. 实验内容
  3. 实验体会
  4. 实验照片

实验目的

利用NEXYS A7及verilog代码制作危险距离报警器,借助pmod模块MaxSonar实现测距功能。应用场景包括:倒车入库刮蹭警示、汽车盲区检测防误伤、极端天气水位警报等。


实验内容

原理描述

1. 流水灯实现
  • 通过计数器cntled_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可以划词翻译,发现以后效率提高了不少。