上篇博文:测了回响脉冲的宽度为多少个10us,这篇博文要算出距离,且用数码管显示距离的十进制结果。

功能框图如下:

距离计算:

还是先给出程序之后在简单解释吧。

顶层模块:

/
//工程硬件平台: Xilinx Spartan 6 FPGA
/
//每100ms产生1个超声波测距模块所需的10us高脉冲激励,并用数码管以10进制数据显示最终经过换算后的距离信息(单位mm)
module sp6(input ext_clk_25m,   //外部输入25MHz时钟信号input ext_rst_n, //外部输入复位信号,低电平有效output ultrasound_trig,  //超声波测距模块脉冲激励信号,10us的高脉冲input ultrasound_echo,       //超声波测距模块回响信号output[3:0] dtube_cs_n,    //7段数码管位选信号output[7:0] dtube_data   //7段数码管段选信号(包括小数点为8段)         );                                                  //-------------------------------------
//PLL例化
wire clk_12m5;  //PLL输出12.5MHz时钟
wire clk_25m;   //PLL输出25MHz时钟
wire clk_50m;   //PLL输出50MHz时钟
wire clk_100m;  //PLL输出100MHz时钟
wire sys_rst_n; //PLL输出的locked信号,作为FPGA内部的复位信号,低电平复位,高电平正常工作pll_controller uut_pll_controller(// Clock in ports.CLK_IN1(ext_clk_25m),      // IN// Clock out ports.CLK_OUT1(clk_12m5),     // OUT.CLK_OUT2(clk_25m),     // OUT.CLK_OUT3(clk_50m),     // OUT.CLK_OUT4(clk_100m),     // OUT// Status and control signals.RESET(~ext_rst_n),// IN.LOCKED(sys_rst_n));      // OUT      //-------------------------------------
//25MHz时钟进行分频,产生一个100KHz频率的时钟使能信号
wire clk_100khz_en; //100KHz频率的一个时钟使能信号,即每10us产生一个时钟脉冲clkdiv_generation  uut_clkdiv_generation(.clk(clk_25m),        //时钟信号.rst_n(sys_rst_n),    //复位信号,低电平有效.clk_100khz_en(clk_100khz_en)    //100KHz频率的一个时钟使能信号,即每10us产生一个时钟脉冲);         //-------------------------------------
//每100ms产生一个10us的高脉冲作为超声波测距模块的激励
wire[15:0] echo_pulse_num;  //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值
wire echo_pulse_en;     //超声波测距模块回响信号计数值有效信号ultrasound_controller   uut_ultrasound_controller(.clk(clk_25m),        //时钟信号.rst_n(sys_rst_n),    //复位信号,低电平有效.clk_100khz_en(clk_100khz_en),   //100KHz频率的一个时钟使能信号,即每10us产生一个时钟脉冲.ultrasound_trig(ultrasound_trig), //超声波测距模块脉冲激励信号,10us的高脉冲.ultrasound_echo(ultrasound_echo),       //超声波测距模块回响信号.echo_pulse_en(echo_pulse_en),     //超声波测距模块回响信号计数值有效信号.echo_pulse_num(echo_pulse_num)     //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值); //-------------------------------------
//缓存最近采集到的8组超声波测距回响脉冲计数值,对它们进行累加并求平均
wire[15:0] echo_pulse_filter_num;   //滤波处理后的超声波测距模块回响信号高脉冲计数值filter     uut_filter(.clk(clk_25m),       //时钟信号.rst_n(sys_rst_n),    //复位信号,低电平有效.echo_pulse_en(echo_pulse_en),       //超声波测距模块回响信号计数值有效信号.echo_pulse_num(echo_pulse_num),        //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值.echo_pulse_filter_num(echo_pulse_filter_num)  //滤波处理后的超声波测距模块回响信号高脉冲计数值); //-------------------------------------
//换算出超声波测距的实际距离,并且以十进制,单位mm形式输出
wire[15:0] echo_pulse_f_mul_num;    //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值,换算为实际距离的10进制数据distance_compute uut_distance_compute(.clk(clk_25m),     //时钟信号.rst_n(sys_rst_n),    //复位信号,低电平有效.echo_pulse_filter_num(echo_pulse_filter_num),   //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值.echo_pulse_f_mul_num(echo_pulse_f_mul_num)    //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值,换算为实际距离的10进制数据);   //-------------------------------------
//4位数码管显示驱动                                                         seg7        uut_seg7(.clk(clk_25m),     //时钟信号.rst_n(sys_rst_n),    //复位信号,低电平有效.display_num(echo_pulse_f_mul_num),      //显示数据  .dtube_cs_n(dtube_cs_n),    //7段数码管位选信号.dtube_data(dtube_data)      //7段数码管段选信号(包括小数点为8段));endmodule

子模块:

/
//工程硬件平台: Xilinx Spartan 6 FPGA
//25°C时,声音在空气中传播的速度为346m/s
//因此取距离s的单位是米(m),时间t的单位是秒(s),有 s = 346*t/2
//若取距离s的单位是毫米(mm),时间t的单位是10微秒(10us),有s*0.001 = 346*t*0.00001/2,即s = 1.73*t
//为了便于计算,取s = ((1.73*256)*t)/256 = (443*t)/256module distance_compute(input clk,       //外部输入25MHz时钟信号input rst_n, //外部输入复位信号,低电平有效input[15:0] echo_pulse_filter_num,   //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值output[15:0] echo_pulse_f_mul_num  //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值,换算为实际距离的10进制数据);                                                           //-------------------------------------------------
//距离换算
wire[31:0] mul_out; //输出的乘法运算结果,取bit23-8为有效的16bit数据mul   uut_mul (.clk(clk), // input clk.a(16'd443), // input [15 : 0] a.b(echo_pulse_filter_num), // input [15 : 0] b.p(mul_out) // output [31 : 0] p);   //-------------------------------------------------
//将16进制数据转换为10进制,由于我们已知有效的16bit数据的有效范围是0-4000mm
wire[15:0] thousand_quotint,thousand_fractional;    //千位除法运算结果与余数寄存器//千位运算
div         thousand_div (.clk(clk), // input clk.rfd(), // output rfd.dividend(mul_out[23:8]), // input [15 : 0] dividend.divisor(16'd1000), // input [15 : 0] divisor.quotient(thousand_quotint), // output [15 : 0] quotient.fractional(thousand_fractional) // output [15 : 0] fractional);    wire[15:0] hundred_quotint,hundred_fractional;  //百位除法运算结果与余数寄存器//百位运算
div         hundred_div (.clk(clk), // input clk.rfd(), // output rfd.dividend(thousand_fractional), // input [15 : 0] dividend.divisor(16'd100), // input [15 : 0] divisor.quotient(hundred_quotint), // output [15 : 0] quotient.fractional(hundred_fractional) // output [15 : 0] fractional);  wire[15:0] ten_quotint,ten_fractional;  //十位除法运算结果与余数寄存器//十位运算
div         ten_div (.clk(clk), // input clk.rfd(), // output rfd.dividend(hundred_fractional), // input [15 : 0] dividend.divisor(16'd10), // input [15 : 0] divisor.quotient(ten_quotint), // output [15 : 0] quotient.fractional(ten_fractional) // output [15 : 0] fractional);assign echo_pulse_f_mul_num = {thousand_quotint[3:0],hundred_quotint[3:0],ten_quotint[3:0],ten_fractional[3:0]};endmodule
/
//工程硬件平台: Xilinx Spartan 6 FPGA
/
module clkdiv_generation(input clk,     //外部输入25MHz时钟信号input rst_n, //外部输入复位信号,低电平有效output clk_100khz_en //100KHz频率的一个时钟使能信号,即每10us产生一个时钟脉冲);                                                         //-------------------------------------------------
//时钟分频产生
reg[7:0] cnt;   //时钟分频计数器,0-249//1s定时计数
always @(posedge clk or negedge rst_n)if(!rst_n) cnt <= 8'd0;else if(cnt < 8'd249) cnt <= cnt+1'b1;else cnt <= 8'd0;assign clk_100khz_en = (cnt == 8'd249) ? 1'b1:1'b0;      //每40us产生一个40ns的高脉冲             endmodule
/
//工程硬件平台: Xilinx Spartan 6 FPGA
/
module ultrasound_controller(input clk,     //外部输入25MHz时钟信号input rst_n, //外部输入复位信号,低电平有效input clk_100khz_en, //100KHz频率的一个时钟使能信号,即每10us产生一个时钟脉冲output ultrasound_trig,    //超声波测距模块脉冲激励信号,10us的高脉冲input ultrasound_echo,       //超声波测距模块回响信号output reg echo_pulse_en,      //超声波测距模块回响信号计数值有效信号output reg[15:0] echo_pulse_num //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值);                                                         //-------------------------------------------------
//1s定时产生逻辑
reg[13:0] timer_cnt;    //1s计数器,以100KHz(10us)为单位进行计数,计数100ms需要的计数范围是0~9999//1s定时计数
always @(posedge clk or negedge rst_n)if(!rst_n) timer_cnt <= 14'd0;else if(clk_100khz_en) beginif(timer_cnt < 14'd9_999) timer_cnt <= timer_cnt+1'b1;else timer_cnt <= 14'd0;endelse ;assign ultrasound_trig = (timer_cnt == 14'd1) ? 1'b1:1'b0;        //10us高脉冲生成                     //-------------------------------------------------
//超声波测距模块的回响信号echo打两拍,产生上升沿和下降沿标志位
reg[1:0] ultrasound_echo_r;always @(posedge clk or negedge rst_n)if(!rst_n) ultrasound_echo_r <= 2'b00;else ultrasound_echo_r <= {ultrasound_echo_r[0],ultrasound_echo};wire pos_echo = ~ultrasound_echo_r[1] & ultrasound_echo_r[0];    //echo信号上升沿标志位,高电平有效一个时钟周期
wire neg_echo = ultrasound_echo_r[1] & ~ultrasound_echo_r[0];  //echo信号下降沿标志位,高电平有效一个时钟周期//-------------------------------------------------
//以10us为单位对超声波测距模块回响信号高脉冲进行计数
reg[15:0] echo_cnt;     //回响高脉冲计数器always @(posedge clk or negedge rst_n)if(!rst_n) echo_cnt <= 16'd0;else if(pos_echo) echo_cnt <= 16'd0;    //计数清零else if(clk_100khz_en && ultrasound_echo_r[0]) echo_cnt <= echo_cnt+1'b1;else ;//计数脉冲数锁存
always @(posedge clk or negedge rst_n)if(!rst_n) echo_pulse_num <= 16'd0; else if(neg_echo) echo_pulse_num <= echo_cnt;//计数脉冲有效使能信号锁存
always @(posedge clk or negedge rst_n)if(!rst_n) echo_pulse_en <= 1'b0;else echo_pulse_en <= neg_echo;endmodule
/
//工程硬件平台: Xilinx Spartan 6 FPGA
/
//缓存最近采集到的8组超声波测距回响脉冲计数值,对它们进行累加并求平均
module filter(input clk,        //外部输入25MHz时钟信号input rst_n, //外部输入复位信号,低电平有效input echo_pulse_en,     //超声波测距模块回响信号计数值有效信号input[15:0] echo_pulse_num, //以10us为单位对超声波测距模块回响信号高脉冲进行计数的最终值output[15:0] echo_pulse_filter_num //滤波处理后的超声波测距模块回响信号高脉冲计数值);                                                         //-------------------------------------------------
//echo_pulse_num信号缓存10拍
reg[15:0] pulse_reg[7:0];   //echo_pulse_num信号缓存寄存器always @(posedge clk or negedge rst_n)if(!rst_n) beginpulse_reg[0] <= 16'd0;pulse_reg[1] <= 16'd0;pulse_reg[2] <= 16'd0;pulse_reg[3] <= 16'd0;pulse_reg[4] <= 16'd0;pulse_reg[5] <= 16'd0;pulse_reg[6] <= 16'd0;pulse_reg[7] <= 16'd0;endelse if(echo_pulse_en) begin   //缓存最新的数据,使用移位寄存器的方式推进最新数据,推出最老的数据pulse_reg[0] <= echo_pulse_num;pulse_reg[1] <= pulse_reg[0];pulse_reg[2] <= pulse_reg[1];pulse_reg[3] <= pulse_reg[2];pulse_reg[4] <= pulse_reg[3];pulse_reg[5] <= pulse_reg[4];pulse_reg[6] <= pulse_reg[5];pulse_reg[7] <= pulse_reg[6];end//-------------------------------------------------
//对8个数据累加并输出平均值
reg[15:0] sum_pulse_reg;always @(posedge clk or negedge rst_n)if(!rst_n) sum_pulse_reg <= 16'd0;else sum_pulse_reg <= pulse_reg[0]+pulse_reg[1]+pulse_reg[2]+pulse_reg[3]+pulse_reg[4]+pulse_reg[5]+pulse_reg[6]+pulse_reg[7];assign echo_pulse_filter_num = {3'b000,sum_pulse_reg[15:3]};   //右移3位,相当于除以8endmodule
/
//工程硬件平台: Xilinx Spartan 6 FPGA
/
module seg7(input clk,      //时钟信号,25MHzinput rst_n, //复位信号,低电平有效input[15:0] display_num, //数码管显示数据,[15:12]--数码管千位,[11:8]--数码管百位,[7:4]--数码管十位,[3:0]--数码管个位output reg[3:0] dtube_cs_n, //7段数码管位选信号output reg[7:0] dtube_data   //7段数码管段选信号(包括小数点为8段));//-------------------------------------------------
//参数定义//数码管显示 0~F 对应段选输出
parameter   NUM0    = 8'h3f,//c0,NUM1     = 8'h06,//f9,NUM2     = 8'h5b,//a4,NUM3     = 8'h4f,//b0,NUM4     = 8'h66,//99,NUM5     = 8'h6d,//92,NUM6     = 8'h7d,//82,NUM7     = 8'h07,//F8,NUM8     = 8'h7f,//80,NUM9     = 8'h6f,//90,NUMA     = 8'h77,//88,NUMB     = 8'h7c,//83,NUMC     = 8'h39,//c6,NUMD     = 8'h5e,//a1,NUME     = 8'h79,//86,NUMF     = 8'h71,//8e;NDOT = 8'h80;  //小数点显示//数码管位选 0~3 对应输出
parameter   CSN     = 4'b1111,CS0     = 4'b1110,CS1     = 4'b1101,CS2     = 4'b1011,CS3     = 4'b0111;//-------------------------------------------------
//分时显示数据控制单元
reg[3:0] current_display_num;   //当前显示数据
reg[7:0] div_cnt;   //分时计数器//分时计数器
always @(posedge clk or negedge rst_n)if(!rst_n) div_cnt <= 8'd0;else div_cnt <= div_cnt+1'b1;//显示数据
always @(posedge clk or negedge rst_n)if(!rst_n) current_display_num <= 4'h0;else begincase(div_cnt)8'hff: current_display_num <= display_num[3:0];8'h3f: current_display_num <= display_num[7:4];8'h7f: current_display_num <= display_num[11:8];8'hbf: current_display_num <= display_num[15:12];default: ;endcaseend//段选数据译码
always @(posedge clk or negedge rst_n)if(!rst_n) dtube_data <= NUM0;else begincase(current_display_num) 4'h0: dtube_data <= NUM0;4'h1: dtube_data <= NUM1;4'h2: dtube_data <= NUM2;4'h3: dtube_data <= NUM3;4'h4: dtube_data <= NUM4;4'h5: dtube_data <= NUM5;4'h6: dtube_data <= NUM6;4'h7: dtube_data <= NUM7;4'h8: dtube_data <= NUM8;4'h9: dtube_data <= NUM9;4'ha: dtube_data <= NUMA;4'hb: dtube_data <= NUMB;4'hc: dtube_data <= NUMC;4'hd: dtube_data <= NUMD;4'he: dtube_data <= NUME;4'hf: dtube_data <= NUMF;default: ;endcaseend//位选译码
always @(posedge clk or negedge rst_n)if(!rst_n) dtube_cs_n <= CSN;else begincase(div_cnt[7:6])2'b00: dtube_cs_n <= CS0;2'b01: dtube_cs_n <= CS1;2'b10: dtube_cs_n <= CS2;2'b11: dtube_cs_n <= CS3;default:  dtube_cs_n <= CSN;endcaseendendmodule

其他,前几篇博文已经讲了。这里重点讲讲模块distance_compute:

原理:

//25°C时,声音在空气中传播的速度为346m/s
//因此取距离s的单位是米(m),时间t的单位是秒(s),有 s = 346*t/2
//若取距离s的单位是毫米(mm),时间t的单位是10微秒(10us),有s*0.001 = 346*t*0.00001/2,即s = 1.73*t
//为了便于计算,取s = ((1.73*256)*t)/256 = (443*t)/256

关于443与脉宽t相乘,用了一个相乘的IP核,IP核模板为:

mul your_instance_name (
  .clk(clk), // input clk
  .a(a), // input [15 : 0] a
  .b(b), // input [15 : 0] b
  .p(p) // output [31 : 0] p
);

//距离换算
wire[31:0] mul_out;    //输出的乘法运算结果,取bit23-8为有效的16bit数据
    
mul     uut_mul (
          .clk(clk), // input clk
          .a(16'd443), // input [15 : 0] a
          .b(echo_pulse_filter_num), // input [15 : 0] b
          .p(mul_out) // output [31 : 0] p
        );

相乘的结果是32位的mul_out;

之后对这个结果进行除以256以及转换为10进制的运算:

除以256相当于被除数右移8位,并且被除数有最大值,可以确定32位中的多少位有数,这里是mul_out[23:8],作为结果。

之后除以1000得到结果作为十进制的千位,余数除以100,得到结果作为百位,余数除以10得到十位,余数作为个位。

程序体现:

wire[15:0] thousand_quotint,thousand_fractional;    //千位除法运算结果与余数寄存器

//千位运算
div         thousand_div (
                .clk(clk), // input clk
                .rfd(), // output rfd
                .dividend(mul_out[23:8]), // input [15 : 0] dividend
                .divisor(16'd1000), // input [15 : 0] divisor
                .quotient(thousand_quotint), // output [15 : 0] quotient
                .fractional(thousand_fractional) // output [15 : 0] fractional
            );    
    
wire[15:0] hundred_quotint,hundred_fractional;    //百位除法运算结果与余数寄存器

//百位运算
div         hundred_div (
                .clk(clk), // input clk
                .rfd(), // output rfd
                .dividend(thousand_fractional), // input [15 : 0] dividend
                .divisor(16'd100), // input [15 : 0] divisor
                .quotient(hundred_quotint), // output [15 : 0] quotient
                .fractional(hundred_fractional) // output [15 : 0] fractional
            );

wire[15:0] ten_quotint,ten_fractional;    //十位除法运算结果与余数寄存器
            
    //十位运算
div         ten_div (
                .clk(clk), // input clk
                .rfd(), // output rfd
                .dividend(hundred_fractional), // input [15 : 0] dividend
                .divisor(16'd10), // input [15 : 0] divisor
                .quotient(ten_quotint), // output [15 : 0] quotient
                .fractional(ten_fractional) // output [15 : 0] fractional
            );

assign echo_pulse_f_mul_num = {thousand_quotint[3:0],hundred_quotint[3:0],ten_quotint[3:0],ten_fractional[3:0]};

【 FPGA 】超声波测距小实验(四):数码管显示测距结果相关推荐

  1. 实验四 数码管显示设计与仿真

    4.1实验目的 熟练掌握组合逻辑电路的设计.掌握不定位宽乘法器以及7段数码管(不带小数点)显示原理.实现并仿真: 1)4位乘法器及数码管显示: 4.2实验内容 (1)设计4位乘法器,并将被乘数,乘数, ...

  2. 【 FPGA 】超声波测距小实验(一)

    超声波测距原理: 超声波测距原理是在超声波发射装置发出超声波,它的根据是接收器接到超声波时的时间差,与雷达测距原理相似. 超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播 ...

  3. 实验24:超声波测距仪小实验

    --超声波测距小实验 --液晶显示距离 OK,简单分享一个小实验,超声波测距实验 01 硬件电路 超声波传感器 液晶 总体电路连接 接口: 第1步:建立电路 超声波传感器与 Arduino Uno 板 ...

  4. Arduino + ESP32-C3 + TFT(1.8‘ ST7735S)基础平台(实验四)直接显示网络图片

    ---------------------------------------------------------------------------------------------------- ...

  5. FPGA学习汇总(六)----数码管显示(1)

    目录 概念 单个数码管显示单个数字 操作 代码 现象 分析 四个数码管定时单个显示数字 分析 代码 四个数码管同时显示 分析 代码 现象 四个数码管同时显示定时转换 分析 代码 概念 我们要搞懂数码管 ...

  6. 【Arduino实验10 数码管显示】

    目录 一.实验目的 二.实验设备与环境 三.实验重点 四.实验难点 五.实验内容 5.1实验任务 5.2实验原理 5.3实验内容 5.4实验结果 5.5思考题 一.实验目的 (1)掌握1位数码管模块的 ...

  7. 【 FPGA 】控制数码管动态扫描显示的小实验

    实验的功能很简单,就是让4个数码管每隔1s递增显示,使用动态扫描的方式来实现. 从这个功能的描述可以看出,我们首先要写一个计数器模块,来让计数值每隔1s增加1,暂时实现的是16进制的东西,从0到f,之 ...

  8. 【正点原子FPGA连载】第三十一章RTC实时时钟数码管显示实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

    1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:ht ...

  9. arduino UNO 与 超声波测距模块 实验详情

    US-015 超声波测距模块 超声波传感器 US-020升级版 送全套资料 资料下载地址:http://pan.baidu.com/s/1c0AfkIG US-015超声波测距模块 1. 概述 US- ...

最新文章

  1. linux paste变量,Linux paste命令详解
  2. html兼容不同屏幕 代码,rem的正确使用姿势 -- 完美解决H5页面不同尺寸屏幕的适配问题...
  3. 出道50+年!乘风破浪的编程语言们,能二次翻红吗?
  4. L2-009. 抢红包 结构体排序
  5. python读取文件的常用方法
  6. 急速收藏:4套iOS SDK的H5打通方案
  7. how to figure out problems in the ardunio nano force senser? 1,2,3,4
  8. mysql5.7环境,MySQL-5.7-线上生产环境部署
  9. php 中文截断,PHP中实现中文字串截取无乱码的解决方法
  10. php MySQL定义,PHP + MySQL用户定义函数
  11. NSString常用方法
  12. 2014 Super Training #2 F The Bridges of Kolsberg --DP
  13. 《深入理解Java虚拟机》读书笔记十二
  14. Redis基础--使用treeNMS管理及监控Redis
  15. CF1060F Shrinking Tree
  16. 持续更新 iText in Action 2nd Edition中文版 个人翻译
  17. java控制台实现的简易计算器,实现加减乘除
  18. 【数据库】什么是 PostgreSQL?开源数据库系统
  19. 中国人寿保险软件开发机试题 java实现
  20. 将来用NFC也能付支付宝、微信里的钱?NFC Forum发布一项新规范

热门文章

  1. 2021年中国LED工业照明市场趋势报告、技术动态创新及2027年市场预测
  2. 性能测试模型初探及应用方法分析
  3. Python常用库 - 【持续整理归档】
  4. xHiveAI-A311D:AI开发套件
  5. 线性方程组个数和方程未知数与方程解的关系
  6. 微信小程序识别图片并提取文字_这款微信小程序可以批量图片转文字?识别准确率超高!...
  7. 响铃:“消费茧房”才是拼多多最像今日头条的地方
  8. Linux下十大命令行下载工具
  9. 解决CentOS下boost安装后不能使用的问题
  10. okhttp3与okhttp的区别