基于FPGA的超声波测距——数码管显示

news2024/11/25 5:54:52

文章目录

  • 前言
  • 一、超声波模块介绍
    • 1、产品特点
    • 2、超声波模块的时序图
  • 二、系统设计
    • 1、系统框图
    • 2、源码
    • 3、RTL视图
    • 4、效果
  • 三、总结
  • 四、参考资料


前言

环境:
1、Quartus18.1
2、vscode
3、板子型号:EP4CE6F17C8N
4、超声波模块:HC_SR04
要求:
使用 EP4CE6F17C8开发板驱动 超声波检测模块(HC_SR04 ),并将所测得数据显示到开发板上的数码管上


一、超声波模块介绍

1、产品特点

HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超声波发射器、接收器与控制电路。
基本工作原理:

(1)采用IO口 TRIG触发测距,给最少10us的高电平信呈。
(⑵)模块自动发送8个40khz的方波,自动检测是否有信号返回;
(3)有信号返回,通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2;

在这里插入图片描述

2、超声波模块的时序图

在这里插入图片描述

以上时序图表明你只需要提供一个10uS 以上脉冲触发信号,该模块内部将发出8个40kHz周期电平并检测回波。一旦检测到有回波信号则输出回响信号。回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。

二、系统设计

1、系统框图

在这里插入图片描述

2、源码

  • HC_SR04_TOP顶层文件:
module 	HC_SR04_TOP(
	input  			clk		, 
	input   		rstn	, 
	
	input   		echo	, // 距离信号
	output   		trig	, // 触发测距信号
	output  wire [5:0]	sel	,
	output  wire [7:0]	seg
);

	wire	[18:00]		data_o		;
	wire 				clk_us		;

	seg_driver u_seg_driver(  
		.clk		(clk	),
		.rstn		(rstn	),
		.data_in	(data_o	), //待显示数据
		.sel		(sel	),	// 我这里是8位段选,可以换6位,但是要自己改代码
    	.seg		(seg	)     
	);	

	clk_div	u_clk_div(
		.clk		(clk	), 
		.rstn		(rstn	),
		.clk_us		(clk_us )
	);
	trig_driver	u_trig_driver(
		.clk_us		(clk_us	),
		.rstn		(rstn	),
		.trig		(trig	)
	);

	echo_driver	u_echo_driver(
		.clk		(clk	),
		.clk_us		(clk_us	),
		.rstn		(rstn	),
		.echo		(echo	),
		.data_o		(data_o	)
		);

//Logic Description
endmodule 

  • trig_driver超声波驱动模块:
module 	trig_driver(
	input  wire			clk_us	,
	input  wire 		rstn	,
		   
	output wire  		trig	  //触发测距信号
);

	parameter CYCLE_MAX = 19'd29_9999;

	reg		[18:00]	cnt		;

// 10毫秒持续电平输出
	
	always @(posedge clk_us or negedge rstn) begin
		if(!rstn) begin
			cnt <= 19'd0;
		end
		else if(cnt == CYCLE_MAX) begin
			cnt <= 19'd0;
		end
		else begin
			cnt <= cnt + 19'd1;
		end
	end
	
	assign trig = cnt < 15 ? 1'b1 : 1'b0;

endmodule 
  • echo_driver测距模块:
module 	echo_driver(
	input  wire 		clk		,
	input  wire			clk_us	,
	input  wire 		rstn	,
		   
	input  wire 		echo	,
	output wire [18:00]	data_o	  //检测距离,保留3位小数,*1000实现
);

	parameter T_MAX = 16'd5_9999;//510cm 对应计数值

	reg				r1_echo,r2_echo; //边沿检测	
	wire			echo_pos,echo_neg; //
	
	reg		[15:00]	cnt		; 
	
	reg		[18:00]	data_r	;
	
	//如果使用clk_us 检测边沿,延时2us,差值过大
	always @(posedge clk or negedge rstn)begin  
		if(!rstn)begin  
			r1_echo <= 1'b0;
			r2_echo <= 1'b0;
		end  
		else begin  
			r1_echo <= echo;
			r2_echo <= r1_echo;
		end  
	end
	
	assign echo_pos = r1_echo & ~r2_echo;
	assign echo_neg = ~r1_echo & r2_echo;
	
	always @(posedge clk_us or negedge rstn) begin
		if(!rstn) begin
			cnt <= 16'd0;
		end
		else if(echo) begin
			if(cnt == T_MAX) begin
				cnt <= 16'd0;
			end
			else begin
				cnt <= cnt + 16'd1;
			end
		end
		else begin
			cnt <= 16'd0;
		end
	end
	
	always @(posedge clk or negedge rstn)begin  
		if(!rstn)begin  
			data_r <= 'd2;
		end  
		else if(echo_neg)begin  
			data_r <= (cnt << 4) + cnt;
		end  
		else begin  
			data_r <= data_r;
		end  
	end
	
	assign data_o = data_r >> 1;

endmodule 

  • 时钟分频模块:
module 	clk_div(
	input  wire			clk		,
	input  wire 		rstn	,
		   
	output wire  		clk_us 	  //
);

	parameter CNT_MAX = 19'd49;//1us的计数值为 50 * Tclk(20ns)

	reg		[5:0]	cnt		; 
	wire			add_cnt ;
	wire			end_cnt ;
	
	// 时钟分频
	always @(posedge clk or negedge rstn) begin
		if(!rstn) begin
			cnt <= 6'd0;
		end
		else if(cnt == CNT_MAX) begin
			cnt <= 6'd0;
		end
		else begin
			cnt <= cnt + 6'd1;
		end
	end
	
	assign clk_us = cnt >= CNT_MAX ;
	

endmodule 

  • seg_driver数码管驱动模块:
module seg_driver(  
	input	wire		clk		,
	input	wire		rstn	,
	
	input	wire [18:0]	data_in	, //待显示数据

    output  reg [5:0]   sel     ,	// 我这里是8位段选,可以换6位,但是要自己改代码
    output  reg [7:0]   seg     
);								  
 	//parameter define  
	localparam	NUM_0	=	8'b1100_0000,	
				NUM_1 	= 	8'b1111_1001,
				NUM_2   = 	8'b1010_0100,
				NUM_3   = 	8'b1011_0000,
				NUM_4   = 	8'b1001_1001,
				NUM_5   = 	8'b1001_0010,
				NUM_6   = 	8'b1000_0010,
				NUM_7   = 	8'b1111_1000,
				NUM_8   = 	8'b1000_0000,
				NUM_9   = 	8'b1001_0000,
				NUM_A   = 	8'b1000_1000,
				NUM_B   = 	8'b1000_0011,
				NUM_C   = 	8'b1100_0110,
				NUM_D   = 	8'b1010_0001,
				NUM_E   = 	8'b1000_0110,
				NUM_F   = 	8'b1000_1110,
				ALL_LIGHT = 8'b0000_0000,
				LIT_OUT = 	8'b1111_1111,
                LINE    =   8'b1011_1111;

    localparam MAX_10us     =   10'd999     ;
 	//reg 、wire define		
	reg		[3:0]	cm_hund	    ;//100cm
	reg		[3:0]	cm_ten	    ;//10cm
	reg		[3:0]	cm_unit	    ;//1cm
	reg		[3:0]	point_1	    ;//1mm
	reg		[3:0]	point_2	    ;//0.1mm
	reg		[3:0]	point_3	    ;//0.01mm
    reg     [9:0]   cnt_10us    ;
    reg     [7:0]   num         ;// 段选输出判断

	always @(posedge clk or negedge rstn)begin  
		if(!rstn)begin  
			cm_hund	<= 'd0;
			cm_ten	<= 'd0;
			cm_unit	<= 'd0;
			point_1	<= 'd0;
			point_2	<= 'd0;
			point_3	<= 'd0;
		end  
		else begin  
			cm_hund <= data_in / 10 ** 5;
			cm_ten	<= data_in / 10 ** 4 % 10;
			cm_unit <= data_in / 10 ** 3 % 10;
			point_1 <= data_in / 10 ** 2 % 10;
			point_2 <= data_in / 10 ** 1 % 10;
			point_3 <= data_in / 10 ** 0 % 10;
		end  
	end 

    // 修改后   段选

	always @(posedge clk or negedge rstn) begin
		if(!rstn) begin
			cnt_10us <= 10'd0;
		end
		else if(cnt_10us == MAX_10us) begin
			cnt_10us <= 10'd0;
		end
		else begin
			cnt_10us <= cnt_10us + 10'd1;
		end
	end

    // 数码管位移
    always @(posedge clk or negedge rstn) begin
        if(!rstn) begin
            sel <= 6'b111_110;
        end
        else if(cnt_10us == MAX_10us) begin
            sel <= {sel[0],sel[5:1]};
        end
        else begin
            sel <= sel;
        end
    end

    // 确定输出数字
    always @(*) begin
        case (sel)
			6'b01_1111	:    num = hex_data(point_3);
			6'b10_1111	:    num = hex_data(point_2);
			6'b11_0111	:    num = hex_data(point_1);
			6'b11_1011	:    num = hex_data(cm_unit);
			6'b11_1101	:    num = hex_data(cm_ten)	;
			6'b11_1110	:    num = hex_data(cm_hund);
			// 6'b11_1111	:    num = LINE;
			// 6'b11_1111	:    num = LIT_OUT;

            default         :    num = NUM_0;
        endcase
    end

    // 位选输出
    always @(posedge clk or negedge rstn) begin
        if(!rstn) begin
            seg <= LINE;
        end
        else begin
            case (num)
                NUM_0       :   seg <= NUM_0    ;
                NUM_1       :   seg <= NUM_1    ;
                NUM_2       :   seg <= NUM_2    ;
                NUM_3       :   seg <= NUM_3    ;
                NUM_4       :   seg <= NUM_4    ;
                NUM_5       :   seg <= NUM_5    ;
                NUM_6       :   seg <= NUM_6    ;
                NUM_7       :   seg <= NUM_7    ;
                NUM_8       :   seg <= NUM_8    ;
                NUM_9       :   seg <= NUM_9    ;
                LINE        :   seg <= LINE     ;
                LIT_OUT     :   seg <= LIT_OUT  ;
                ALL_LIGHT   :   seg <= ALL_LIGHT;
            endcase
        end
    end

    // 函数,4位输入,7位输出,判断要输出的数字
    function  [7:0]	hex_data; //函数不含时序逻辑相关
		input   [03:00]	data_i;//至少一个输入
		begin
			case(data_i)
				4'd0:hex_data = NUM_0;
				4'd1:hex_data = NUM_1;
				4'd2:hex_data = NUM_2;
				4'd3:hex_data = NUM_3;
				4'd4:hex_data = NUM_4;
				4'd5:hex_data = NUM_5;
				4'd6:hex_data = NUM_6;
				4'd7:hex_data = NUM_7;
				4'd8:hex_data = NUM_8;
				4'd9:hex_data = NUM_9;
				default:hex_data = ALL_LIGHT;
			endcase	
		end 
	endfunction

endmodule  

3、RTL视图

在这里插入图片描述

4、效果

超声波测距


三、总结

数码管的前三位表示百、十、个的厘米单位,后三位为保留小数位,总体来说测距模块还是相对准确的。通过这次的操作,基本理解了超声波模块的使用驱动原理,对数码管的操作更加熟练。

四、参考资料

基于DE2 115开发板驱动HC_SR04超声波测距模块【附源码】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/555151.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【持续集成CI/持续部署CD】二、Docker安装Maven私服Nexus

本文是关于通过 Docker 进行安装部署 Nexus3 私服的快速入门和简单使用案例。 一、安装 1. 通过 docker 获取最新版本的 nexus3 镜像 docker pull sonatype/nexus3创建 docker 镜像到宿主机的磁盘映射目录Linux:mkdir -p /home/nexus/datachmod 777 -R /home/nexus/dataWind…

ThingsBoard的Actor系统如何初始化

1、概述 大家都知道ThingsBoard中使用了Actor,使用这个可以避免多线程并发问题,上一篇我查询资料总结了一下关于Actor的内容,actor不是通过new 一个对象来创建,而是通过一个ActorSystem来创建,下面我将带领大家来学习ThingsBoard启动时Actor如何创建。 2、ThingsBoard的…

【建议收藏】|某大型金融集团内部数据治理实战总结

对于你喜欢的事想去做的事,你必须付出百分之一千的努力你知道这一路可能会有很多困难&#xff0c;会有坚持不下去想要放弃的时候也有时候&#xff0c;你不一定会得到你想要的结果,但你—定要相信。 公众号&#xff1a;857Hub 转发领取PDF全集一份~~~ 数据治理 数字转型&…

传输层协议

目录 传输层 端口号 端口号范围划分 认识知名端口号(Well-Know Port Number) netstat pidof UDP协议UDP协议端格式​编辑 UDP的特点 面向数据报 UDP的缓冲区 UDP使用注意事项 基于UDP的应用层协议 TCP协议 TCP协议段格式 确认应答(ACK)机制 超时重传机制 连…

LDR6020 Type-C PD显示器方案简介

笔记本的视频输出接口一般有VGA、HDMI、DP、Type-C四种。 自从战66一代之后&#xff0c;VGA就基本上已经销声匿迹了&#xff0c;所以目前还是以HDMI和DP接口更为常见。 如果你的笔记本只支持HDMI1.4&#xff0c;那么你外接显示器的上限就只能是2K60或者是1080P144&#xff0c;…

20230522-win11删除文件失败-需要SYSTEM提供的权限

20230522-win11删除文件失败-需要SYSTEM提供的权限 一、软件环境 标签&#xff1a;win11 SYSTEM权限分栏&#xff1a;windows编译器&#xff1a;VS2019 二、问题描述 删除D:\WindowsApps\36186RuoFan.USB_5.8.1.0_x64__q3e6crc0w375t目录下的文件时&#xff0c;提示【文件访…

网络安全合规-数据分类分级具体操作

数据的安全防护&#xff0c;前提在于数据的分级分类。不同类别&#xff0c;不同安全等级的数据&#xff0c;防护手段和要求也是不尽相同的。 数据分类分级整体工作内容&#xff1a; 基础数据资产盘点 通过业务调研及技术探测&#xff0c;对企业的数据库进行全面扫描&#xff0c…

【leetcode】989.数组形式的整数加法

在刷题过程中&#xff0c;遇到此题&#xff0c;自己水平有限做不出来&#xff0c;查看众多题解&#xff0c;找到一个通俗易懂的思路&#xff0c;在此我将分享给大家这个解题过程&#xff01; 题目描述&#xff1a; 整数的 数组形式 num 是按照从左到右的顺序表示其数字的数组…

探索Java面向对象编程的奇妙世界(一)

现实世界中&#xff0c;随处可见的一种事务就是对象&#xff0c;对象是事务存在的实体&#xff0c;如人、书桌、计算机、高楼大厦等。人类解决问题的方式总是将复杂的事务简单化&#xff0c;于是就会思考这些对象都是由哪些部分组成的。下面我来带大家了解面向对象吧。 ⭐ 面向…

Anaconda安装与Python环境搭建

这篇文章介绍了如何安装Anaconda&#xff0c;及Python环境如何配置&#xff0c;你是否还在为难以寻找一篇讲述全面的环境配置博客而苦恼&#xff0c;稍安勿躁&#xff0c;你找对啦&#xff0c;照着本篇文章做下去&#xff0c;你就会发现没那么难呢&#xff01; Anaconda安装 …

记一次 .NET 某汽贸店 CPU 爆高分析

一&#xff1a;背景 1. 讲故事 上周有位朋友在 github 上向我求助&#xff0c;说线程都被卡住了&#xff0c;让我帮忙看下&#xff0c;截图如下&#xff1a; 时隔两年 终于有人在上面提 Issue 了&#xff0c;看样子这块以后可以作为求助专区来使用&#xff0c;既然来求助&…

gulimall-商城业务-商品上架

商城业务 前言一、商品上架1.1 商品 Mapping1.2 商品信息保存到es1.3 es数组的扁平化处理1.4 构造基本数据 前言 本文继续记录B站谷粒商城项目视频 P128-135 的内容&#xff0c;做到知识点的梳理和总结的作用&#xff0c;接口文档地址&#xff1a;gulimall接口文档 一、商品上…

面了个字节拿 30K 出来的测试,让我见识到了什么是测试的天花板

人人都有大厂梦&#xff0c;对于软件测试人员来说&#xff0c;BATJ 为首的一线互联网公司肯定是自己的心仪对象&#xff0c;毕竟能到这些大厂工作&#xff0c;不仅薪资高待遇好&#xff0c;而且能力技术都能够得到提升&#xff0c;最关键的是还能够给自己镀上一层金&#xff0c…

jenkins pipline 拉取git历史版本

声明&#xff0c;本文是基于&#xff1a;jenkins流水线&#xff08;jenkinsfile&#xff09;详解&#xff0c;保姆式教程_我认不到你的博客-CSDN博客&#xff0c;以下内容介绍通过 Commit ID 拉取 git 历史版本 Commit ID &#xff08;节点号&#xff09;是什么&#xff1f;&a…

5G配电网专用工业级路由器(电力紧凑型DTU)-智慧电力物联网

随着近年来智能电网的快速发展&#xff0c;它实现了电力系统的监控、数据、电能的统一化智能管理&#xff0c;通过与5G技术结合&#xff0c;助力构建高可靠、高灵活、高效率的配电网络。 5G网络技术具备低时延传输的特点&#xff0c;满足配电网安全、控制的苛刻要求&#xff0…

软件测试面试一定要准备的7个高频面试题(附答案,建议收藏)

收集了很多人在面试时的面试题后&#xff0c;我特意整理出了7个高频出现的面试题&#xff0c;一起来看看。 高频问题1&#xff1a;请自我介绍下&#xff1f; 高频问题2&#xff1a;请介绍下最近做过的项目&#xff1f; 高频问题3&#xff1a;请介绍下你印象深刻的bug&#xff1…

Android网络握手失败问题分析

问题场景 调用某功能云端接口请求&#xff0c;保存如下信息&#xff1a;Web服务通信期间握手期间远程主机关闭连接 javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake分析 由于同一份代码不同机器有的能调用成功&#xff0c;有的调用失…

C#通用的二进制转化为float和double方法

上一篇&#xff0c;我们将32位二进制【或4个字节】转化为float【Real】小数&#xff0c;这次我们使用通用的方法进行二进制转化。 C#中将32位二进制转换为float【Real】十进制类型_斯内科的博客-CSDN博客 二进制转化float(double)方法: //单精度浮点数对应32位 /…

挖出电商店铺详情数据-API接口分享

在今天的互联网时代&#xff0c;电商平台已经成为了我们生活中不可或缺的一部分。淘宝作为全国最大的电商平台之一&#xff0c;其商品信息也越来越丰富&#xff0c;但是如果你想开发一款能够帮助用户购物的应用程序&#xff0c;就必须获取到淘宝的API接口&#xff0c;才能让你的…

【Webpack】前端工程自动化 - require.context实现模块自动化导入

一、介绍 require.context 是基于 webpack 的一个的 api&#xff0c;主要用来实现模块的自动化导入在前端工程中&#xff0c;如果遇到一个文件需要引入很多模块的情况&#xff0c;可以使用这个apirequire.context 会遍历文件夹中的指定文件&#xff0c;然后自动导入&#xff0…