【案例】超声波测距系统设计

1.1 总体设计

1.1.1 概述

学习了明德扬至简设计法和明德扬设计规范,本人用FPGA设计了一个测距系统。该系统采用超声波进行测量距离再在数码管上显示。在本案例的设计过程中包括了超声波的驱动、三线式数码管显示等技术。经过逐步改进、调试等一系列工作后,最终完成了此设计,并进行上板验证,下面将完整的设计记录与大家分享。

1.1.2 设计目标

此系统将实时显示前方障碍与装置之间的距离。

1.1.3 系统结构框图

系统结构框图如下所示:

1.1.4 模块功能

hc_sr04模块实现功能:

该模块通过控制触发信号trig(10us的TTL)使内部循环发出8个40KHZ脉冲即驱动超声波,接收回响信号echo,通过echo得到距离。

显示模块实现功能:

该模块完成了对所测距离通过数码管对其显示。

1.1.5顶层信号

1.1.6顶层代码

module top(

clk ,

rst_n ,

echo ,

trig   ,
sel,
    seg
);


input               clk     ;
input               rst_n   ;
input               echo    ;


output              trig    ;

     
     wire    [3:0]       s_g     ;
     wire    [3:0]       s_s     ;
     wire    [3:0]       s_b     ;
     wire    [3:0]       s_q     ;
     output  [7:0]       sel     ;
     output  [7:0]       seg     ;
     
     hc_sr04 hc_sr04_1(
            .clk      (clk)   ,
            .rst_n    (rst_n) ,
            .echo     (echo)  ,

            .trig     (trig)  ,
    .s_g      (s_g ),
    .s_s      (s_s ),
    .s_b      (s_b ),
    .s_q      (s_q ) 
);

seg_disp u_seg_disp(
    .clk         (clk  ),
    .rst_n       (rst_n),
    .segment_data({s_q,s_b,s_s,s_g}),
    .segment     (seg  ),
    .seg_sel     (sel  ) 
);
     

     

    endmodule

1.2 hc_sr04模块设计

1.2.1 接口信号

1.2.2 设计思路

我们只需要提供一个短期的10uS脉冲触发信号trig,该模块内部将发出8个40kHz周期电平并检测回波,一旦检测到有回波信号则输出回响信号,回响信号echo是一个脉冲的宽度成正比的距离变量,可通过发射信号到收到的回响信号时间间隔可以计算得到距离。建议测量周期为60ms以上,以防止发射信号对回响信号的影响,这里我们采用的是1s测量一次。

时钟计数器cnt0:用于计算 1 秒的时钟个数,加一条件为1,表示一直计数;结束条件为数到 TIME_1S ,表示数到 1 秒就清零。

距离计数器 h_cnt:用于计算flag为高电平的宽度的时间,如果flag为1,h_cnt就加一;每完成1秒计数后h_cnt就变为0,此外h_cnt等于h_cnt。

模块时序图

1.2.3 参考代码

module hc_sr04(

clk ,

rst_n ,

echo ,

trig   ,
s_g    ,
s_s    ,
s_b    ,
s_q      
);


parameter      DATA_W = 14  ;
    parameter                 TIME_1S = 50_000_000;

input               clk     ;
input               rst_n   ;
input               echo    ;

output              trig    ;
output[ 3:0]        s_g     ;    
output[ 3:0]        s_s     ;    
output[ 3:0]        s_b     ;    
output[ 3:0]        s_q     ;    

     
wire                trig    ;
reg   [ 3:0]        s_g     ;    
reg   [ 3:0]        s_s     ;    
reg   [ 3:0]        s_b     ;    
reg   [ 3:0]        s_q     ;    
reg   [DATA_W-1:0]  distance;
     

reg   [25:0]        cnt0    ;
reg   [20:0]        h_cnt   ;
reg                 echo_2  ;
reg                 echo_1  ;
wire                add_cnt0;
wire                end_cnt0;         
wire                flag_h  ;
wire                flag_l  ;
     

    
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt0 <= 0;
    end
    else if(add_cnt0)begin
        if(end_cnt0)
            cnt0 <= 0;
        else
            cnt0 <= cnt0 + 1'b1;
    end
end

assign add_cnt0 = 1;       
assign end_cnt0 = add_cnt0 && cnt0 == TIME_1S - 1;
    
    

assign trig = (cnt0>=500&&cnt0<1000)?1:0;


always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        echo_1 <= 0;
        echo_2 <= 0;
    end
    else begin
        echo_1 <= echo  ;
        echo_2 <= echo_1;
    end
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        h_cnt <= 0;
    end
    else if(add_h_cnt)begin
        if(end_h_cnt)
            h_cnt <= 0;
        else
            h_cnt <= h_cnt + 1;
    end
    else if(end_cnt0)begin
        h_cnt <= 0;
    end
end

assign add_h_cnt = echo_2;       
assign end_h_cnt = 0 ;   



always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        distance <= 0;
    end
    else if(add_cnt0 && cnt0 == 45_000_000-1)begin
        distance <= h_cnt*34/10000;
    end
end



 always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        s_g <= 0;
    end
    else begin
        s_g <= distance%10;
    end
end


always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        s_s <= 0;
    end
    else begin
        s_s <= (distance/10)%10;
    end
end  


always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        s_b <= 0;
    end
    else begin
        s_b <= (distance/100)%10;
    end
end


always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        s_q <= 0;
    end
    else begin
        s_q <= (distance/1000)%10;
    end

end

endmodule

1.3 显示模块设计

1.3.1接口信号

1.3.2设计思路

该模块对数码管的位选信号sel每隔1ms的时间移位一次,也就是1ms循环亮一个灯,由于1ms的频率肉眼观察不出,我们看到的就是4个灯全亮。

对输入距离distance进行求余处理,得到每一位的数据,通过case语句,让每一位数据形成段选信号,通过位选信号的控制显示在对应的数码管上。

1.3.3参考代码

module seg_disp(

clk ,

rst_n ,

segment_data,

segment ,

seg_sel

);

parameter ZERO = 8'b1100_0000 ;

parameter ONE = 8'b1111_1001 ;

parameter TWO = 8'b1010_0100 ;

parameter THREE = 8'b1011_0000 ;

parameter FOUR = 8'b1001_1001 ;

parameter FIVE = 8'b1001_0010 ;

parameter SIX = 8'b1000_0010 ;

parameter SEVEN = 8'b1111_1000 ;

parameter EIGHT = 8'b1000_0000 ;

parameter NINE = 8'b1001_0000 ;

input clk ;

input rst_n ;

input [31:0] segment_data ;

output [7:0 ] segment ;

output [7:0 ] seg_sel ;

reg [7:0 ] segment ;

reg [7:0 ] seg_sel ;

reg [10:0] delay ;

reg [3:0 ] delay_time ;

wire add_delay_time ;

wire end_delay_time ;

wire add_delay ;

wire end_delay ;

wire [3:0 ] segment_tmp ;

always @(posedge clk or negedge rst_n) begin

if (rst_n==0) begin

delay <= 0;

end

else if(add_delay) begin

if(end_delay)

delay <= 0;

else

delay <= delay+1 ;

end

end

assign add_delay = 1;

assign end_delay = add_delay && delay == 2000-1 ;

always @(posedge clk or negedge rst_n) begin

if (rst_n==0) begin

delay_time <= 0;

end

else if(add_delay_time) begin

if(end_delay_time)

delay_time <= 0;

else

delay_time <= delay_time+1 ;

end

end

assign add_delay_time = end_delay;

assign end_delay_time = add_delay_time && delay_time == 8-1 ;

assign segment_tmp = segment_data[(1+delay_time)*4-1 -:4];

always @(posedge clk or negedge rst_n)begin

if(rst_n==1'b0)begin

segment <= ZERO;

end

else begin

case(segment_tmp)

4'd0:segment <= ZERO;

4'd1:segment <= ONE ;

4'd2:segment <= TWO ;

4'd3:segment <= THREE;

4'd4:segment <= FOUR ;

4'd5:segment <= FIVE ;

4'd6:segment <= SIX ;

4'd7:segment <= SEVEN;

4'd8:segment <= EIGHT;

4'd9:segment <= NINE ;

default:begin

segment <= segment;

end

endcase

end

end

always @(posedge clk or negedge rst_n)begin

if(rst_n==1'b0)begin

seg_sel <= 8'b1111_1111;

end

else begin

seg_sel <= ~(8'b1<<delay_time);

end

end

endmodule

1.4 效果和总结

上板验证效果


在这个设计中,使用明德扬的至简设计法,让我的思路非常清晰,逻辑非常严谨,虽然没有做到一遍成功,但在调试过程中我都比较快速的找到问题,并快速解决。对于学习FPGA的同学,我非常推荐使用明德扬至简设计法和明德扬模块进行学习和设计。

教学视频和工程源代码请移步明德扬论坛学习!

好消息!FPGA至简设计200例已更新,👉🏻学习链接:https://pan.baidu.com/s/181l9fKI8BXwR7HuAF-ok0w 提取码:yt5p

【FPGA至简设计200例】毕业设计案例由浅入深步骤性教学明德扬

温馨提示:明德扬2023推出了全新课程------逻辑设计基本功修炼课,降低学习FPGA门槛的同时,增加了学习的趣味性,并组织了考试赢积分活动

http://www.mdy-edu.com/ffkc/415.html

(点击→了解课程详情☝)

相关推荐
吉大一菜鸡2 小时前
FPGA学习(基于小梅哥Xilinx FPGA)学习笔记
笔记·学习·fpga开发
9527华安8 小时前
FPGA实现MIPI转FPD-Link车载同轴视频传输方案,基于IMX327+FPD953架构,提供工程源码和技术支持
fpga开发·架构·mipi·imx327·fpd-link·fpd953
热爱学习地派大星8 小时前
FPGA远程升级 -- FLASH控制
fpga开发
szxinmai主板定制专家16 小时前
【国产NI替代】基于国产FPGA+兆易创新GD32F450的全国产16振动+2转速(24bits)高精度终端采集板卡
fpga开发
szxinmai主板定制专家18 小时前
【国产NI替代】基于FPGA的32通道(24bits)高精度终端采集核心板卡
大数据·人工智能·fpga开发
HIZYUAN1 天前
AGM FPGA如何配置上拉或者下拉电阻
fpga开发
∑狸猫不是猫1 天前
(13)CT137A- 简易音乐盒设计
fpga开发
ThreeYear_s1 天前
基于FPGA 的4位密码锁 矩阵键盘 数码管显示 报警仿真
fpga开发·矩阵·计算机外设
Anin蓝天(北京太速科技-陈)1 天前
252-8路SATAII 6U VPX高速存储模块
fpga开发
如何学会学习?2 天前
2. FPGA基础了解--全局网络
fpga开发