FPGA基于DE2-115开发板驱动HC_SR04超声波测距模块|集成蜂鸣器,led和vga提示功能

文章目录

  • 前言
  • 一、实验原理
  • 二、Verilog文件
    • 2.1 时钟分频
    • 2.2 超声波测距
    • 2.3 超声波驱动
  • 三、实现过程
    • 3.1 模块说明
    • 3.2 引脚分配
  • 三、演示视频
  • 总结
  • 参考


前言

环境

硬件 DE2-115 HC-SR04超声波传感器

软件 Quartus 18.1

目标结果

使用DE2-115开发板驱动HC-SR04模块,并将所测得数据显示到开发板上的数码管。

模拟倒车雷达,集成蜂鸣器,led和vga提示功能

蜂鸣器提示小于20cm1s一响小于10cm0.5s一响
LED提示小于20cm全亮提示
VGA提示小于20cm ,显示 警告warning 图片


一、实验原理

参考上一篇博客

基于STM32的HC-SR04超声波测距(PWM蜂鸣器+滤波算法+数据上云-标准库实现)

二、Verilog文件

2.1 时钟分频

定义时钟分频模块,产生周期为1us的时钟信号

//产生一个以微秒为周期的时钟信号clk_us,该信号可用于驱动一些需要精确时间控制的电路
module 	clk_div(
	input wire Clk				, // 输入系统时钟,50MHz
    input wire Rst_n			, // 输入复位信号,低电平有效
    
    output wire clk_us      // 输出微秒级时钟信号
);

	// 参数声明 1us = 1000ns = 50个时钟周期
	parameter CNT_MAX = 19'd50		;	//1us的计数值为 50 * Tclk(20ns)

	// 内部线网/寄存器声明
	reg [18:0] cnt					;   // 定义一个19位的计数器
	wire add_cnt					;   // 计数器使能信号
	wire end_cnt					;   // 计数器结束信号,达到最大值时有效
	

	// 计数器的寄存器逻辑	
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  // 如果复位信号有效,则计数器清零
			cnt <= 'd0; 
		end  
		else if(add_cnt)begin   // 如果计数器达到最大值,则计数器重置
			if(end_cnt)begin  
				cnt <= 'd0; 
			end  
			else begin   // 否则计数器继续计数
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  
			cnt <= cnt;  // 如果计数器未使能,则保持当前值
		end  
	end 
	
	// 赋值计数器使能信号,始终使计数器有效
	assign add_cnt = 1'b1; 
	// 赋值计数器结束信号,当计数器使能并且计数值达到CNT_MAX - 1时有效
	assign end_cnt = add_cnt && cnt >= CNT_MAX - 19'd1;
	// 赋值输出时钟信号,当计数器达到最大值时输出一个脉冲
	assign clk_us = end_cnt;
	

endmodule 


2.2 超声波测距

  • 实现HC-SR04超声波传感器的触发模块,用于生成触发测距信号(trig)
  • 定义HC-SR04超声波传感器的回声模块,用于测量距离并输出检测距离数据(data_o)
module distance_drive (
    // 输入输出定义
    input       wire                clk                          ,                // 主时钟信号
    input       wire                clk_1                        ,              // 辅助时钟信号,1Mhz
    input       wire                rst_n                        ,              // 复位信号,低电平有效

    input       wire                echo                         ,               // 回声输入,来自超声波传感器
    output      reg                 trig                         ,                // 发射触发信号,控制超声波传感器发射
    output      wire                data_out_vld                 ,      // 数据有效信号,表示距离数据准备好了
    output      wire      [23:0]    distance_data // 距离数据输出,24位宽
);


localparam	MAX_DISTANCE = 117647; //最大距离 4m

parameter	s_idle = 0;//空闲状态
parameter	s_send = 1;//发送触发信号
parameter	s_wait = 2;//等待内部发送脉冲
parameter	s_accept = 3;//检测回响信号
parameter	s_accept_wait = 4;//延时等待


reg								echo_r0			;
reg								echo_r1			;
reg			[ 2:0 ]			    s_current		;
reg			[ 2:0 ]			    s_next			;
reg			[ 22 :0 ]		    cnt				;
reg			[ 22:0 ]			cnt_wait		;
reg			[ 22:0 ]		    cnt_max			;
reg			[ 16:0 ]			cnt_distance	;
// reg			[ 25:0 ]			cnt_distance_r1			;
// reg			[ 19:0 ]			cnt_distance_r2			;

wire							accept_start_sig			;
wire							accept_stop_sig			;
wire							idle_sig			;
wire							send_sig			;
// wire							wait_sig			;
wire							flag_clear_cnt			;
wire							flag_clear_cnt_wait			;
reg			[ 19:0 ]			distance_data_r			;
wire			[ 23:0 ]			distance_data_r1			;

assign idle_sig = s_current == s_idle;
assign send_sig = s_current == s_send && flag_clear_cnt;
// assign wait_sig = s_current == s_wait && flag_clear_cnt_wait;
assign accept_wait_sig = s_current == s_accept_wait &&  flag_clear_cnt_wait;
assign accept_start_sig = s_current == s_wait && echo_r0 && ~echo_r1;
assign accept_stop_sig = s_current == s_accept && (~echo_r0 && echo_r1);


// always @(posedge clk or negedge rst_n) begin
//     if(!rst_n) begin
//         cnt_distance_r1 <= 0;
//         // cnt_distance_r2 <= 0;
//     end
//     else begin
//         cnt_distance_r1 <= cnt_distance * 340 / 100;
//         // cnt_distance_r2 <= cnt_distance_r1 >> 4;
//     end
// end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        echo_r0 <= 0;
        echo_r1 <= 0;
    end
    else begin
        echo_r0 <= echo;
        echo_r1 <= echo_r0;
    end
end
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        s_current <= s_idle;    
    end
    else begin
        s_current <= s_next;
    end
end

always @(*) begin
    case (s_current)
        s_idle : begin
            if(idle_sig) begin
                s_next = s_send;
            end
            else begin
                s_next = s_idle;
            end
        end
        s_send : begin
            if(send_sig) begin
                s_next = s_wait;
            end
            else begin
                s_next = s_send;
            end
        end
        s_wait : begin
            if(accept_start_sig) begin
                s_next = s_accept;
            end
            else begin
                s_next = s_wait;
            end
        end
        s_accept : begin
            if(accept_stop_sig) begin
                s_next = s_accept_wait;
            end
            else begin
                s_next = s_accept;
            end
        end
        s_accept_wait : begin
            if(accept_wait_sig) begin
                s_next <= s_idle;
            end
            else begin
                s_next <= s_accept_wait;
            end
        end
        default: s_next = s_idle;
    endcase
end

//距离
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        distance_data_r <= 0;
    end
    else if(accept_stop_sig) begin
        distance_data_r <= cnt_distance * 340 / 200;
    end
end

//转BCD码
assign     distance_data_r1[3:0]   = distance_data_r % 10;
assign     distance_data_r1[7:4]   = distance_data_r / 10 % 10;
assign     distance_data_r1[11:8]  = distance_data_r / 100 % 10;
assign     distance_data_r1[15:12] = distance_data_r / 1000 % 10;
assign     distance_data_r1[19:16] = distance_data_r / 10000 % 10;
assign     distance_data_r1[23:20] = distance_data_r / 100000 % 10;

assign data_out_vld = accept_wait_sig;
assign distance_data = distance_data_r1;

//回响信号计数器
always @(posedge clk_1 or negedge rst_n) begin
    if(!rst_n) begin
        cnt_distance <= 0;
    end
    else if(accept_start_sig) begin
        cnt_distance <= 0;
    end
    else if(s_current == s_accept) begin
        cnt_distance <= cnt_distance + 1;
    end
    else begin
        cnt_distance <= 0;
    end
end

//发送触发信号
always @(posedge clk_1 or negedge rst_n) begin
    case (s_current)
        s_idle : begin
            trig <= 0;
        end
        s_send : begin
            trig <= 1;
        end
        s_wait : begin
            trig <= 0;
        end
        s_accept : begin
            trig <= 0;
        end
        s_accept_wait : begin
            trig <= 0;
        end
        default: begin
            trig <= 0;
        end
    endcase
end
//等待发送玩脉冲
always @( posedge clk_1 or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt <= 0;
    end
    else if ( s_current == s_send ) begin
        if ( flag_clear_cnt == 9 ) begin
            cnt <= 0;
        end
        else begin
            cnt <= cnt + 1;
        end
    end
    else begin
        cnt <= 0;
    end
end
assign flag_clear_cnt = cnt == 9;

//延时计数器
always @( posedge clk_1 or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt_wait <= 0;
    end
    else if ( s_current == s_accept_wait ) begin
        if ( flag_clear_cnt_wait ) begin
            cnt_wait <= 0;
        end
        else begin
            cnt_wait <= cnt_wait + 1;
        end
    end
    else begin
        cnt_wait <= 0;
    end
end
assign flag_clear_cnt_wait = cnt_wait == 250_000;
endmodule //distance

2.3 超声波驱动

查看平台手册,发现DE2-115开发板不涉及位选信号,每个段选信号都有一个单独的引脚。在这里插入图片描述
数码管驱动器模块代码如下,用于将输入的数据(data_o)转换为对应的数码管显示:

// seg_driver模块定义开始,用于驱动七段显示器
module seg_driver(
    input wire Clk,        // 时钟信号输入
    input wire Rst_n,      // 复位信号输入,低电平有效

    input wire [18:0] data_o, // 输入的数字数据,即测得的距离数据

    //第1个七段显示器的段选信号输出
    output  wire [6:0]  hex1    ,
    output  wire [6:0]  hex2    ,
    output  wire [6:0]  hex3    ,
    output  wire [6:0]  hex4    ,
    output  wire [6:0]  hex5    ,
    output  wire [6:0]  hex6    ,
    output  wire [6:0]  hex7    ,
    output  wire [6:0]  hex8     
);


/*
通过cnt_20us计数器实现动态扫描定时,sel_r选择寄存器用于选择当前激活的七段显示器。
根据sel_r的选择,从data_o中提取相应的数字,并将其转换为七段显示器的段选编码seg_r。
最后,根据sel_r的选择,将seg_r的值赋给对应的七段显示器输出寄存器,并从这些寄存器输出到实际的七段显示器硬件上。
NOTION和FUSHU参数分别定义了消隐和小数点的编码,用于控制七段显示器的显示。
*/

// 参数定义
parameter   NOTION  = 4'd10,// 定义数字"10"用于消隐的编码
            FUSHU   = 4'd11;

parameter   MAX20us = 10'd1000;// 定义20微秒计数器的最大值

reg [9:0]   cnt_20us        ;  // 20微秒计数器
reg [7:0]   sel_r           ;  // 选择寄存器,用于动态扫描控制 片选信号
reg [3:0]   number          ;  // 要显示的数字 0-9
reg [6:0]   seg_r           ;  // 七段显示器的段选编码 段选信号

// 第n个七段显示器的段选编码寄存器
reg [6:0]   hex1_r          ;
reg [6:0]   hex2_r          ;
reg [6:0]   hex3_r          ;
reg [6:0]   hex4_r          ;
reg [6:0]   hex5_r          ;
reg [6:0]   hex6_r          ;
reg [6:0]   hex7_r          ;
reg [6:0]   hex8_r          ;



// 20微秒计数器逻辑,用于动态扫描定时
always @(posedge Clk or negedge Rst_n) begin
    if (!Rst_n) begin
        cnt_20us <= 10'd0;
    end
    else if (cnt_20us == MAX20us - 1'd1) begin
        cnt_20us <= 10'd0;
    end
    else begin
        cnt_20us <= cnt_20us + 1'd1;
    end
end



// 单个信号sel_r位 片选 拼接约束,实现动态扫描
always @(posedge Clk or negedge Rst_n) begin
    if (!Rst_n) begin
        sel_r <= 8'b11_11_11_10;
    end
    else if (cnt_20us == MAX20us - 1'd1) begin
        sel_r <= {sel_r[6:0],sel_r[7]};//向左循环移动
    end
    else begin
        sel_r <= sel_r;
    end
end

// 根据选择信号sel_r获取要显示的数字
always @(*) begin
    case (sel_r)//片选信号
        8'b11_11_11_10:     number  = NOTION                                        ;//1
        8'b11_11_11_01:     number  = data_o/10_0000                                ;//2
        8'b11_11_10_11:     number  = (data_o%10_0000)/1_0000                       ;//3
        8'b11_11_01_11:     number  = ((data_o%10_0000)%1_0000)/1000                ;//4
        8'b11_10_11_11:     number  = FUSHU                                         ;//5
        8'b11_01_11_11:     number  = (((data_o%10_0000)%1_0000)%1000)/100          ;//6
        8'b10_11_11_11:     number  = ((((data_o%10_0000)%1_0000)%1000)%100)/10     ;//7
        8'b01_11_11_11:     number  = ((((data_o%10_0000)%1_0000)%1000)%100)%10     ;//8
        default:            number  = 4'd0                                          ;
    endcase
end

// 根据数字解析出对应的七段显示器段选值seg_r, 低电平点亮,高电平熄灭
always @(*) begin
    case (number)                   //654_3210     
        4'd0    :       seg_r   =  7'b100_0000;//_    7 段数码管的点在 DE2-115 开发板上是不可用的。
        4'd1    :       seg_r   =  7'b111_1001;//1
        4'd2    :       seg_r   =  7'b010_0100;//2
        4'd3    :       seg_r   =  7'b011_0000;//3
        4'd4    :       seg_r   =  7'b001_1001;//4
        4'd5    :       seg_r   =  7'b001_0010;//5
        4'd6    :       seg_r   =  7'b000_0010;//6
        4'd7    :       seg_r   =  7'b111_1000;//7
        4'd8    :       seg_r   =  7'b000_0000;//8
        4'd9    :       seg_r   =  7'b001_0000;//9
        NOTION  :       seg_r   =  7'b111_1111;// 灭 定义消隐的编码
        FUSHU   :       seg_r   =  7'b111_0111;// 定义小数点的编码
        default :       seg_r   =  7'b111_1111;// 默认消隐
    endcase
end


//根据片选信号sel_r
// 根据选择信号sel_r将seg_r值赋给对应的七段显示器寄存器
always @(*) begin
    case (sel_r)//sel_r片选信号
		8'b11_11_11_10:     hex1_r = seg_r;//seg_r段选信号
		8'b11_11_11_01:     hex2_r = seg_r;
		8'b11_11_10_11:     hex3_r = seg_r;
		8'b11_11_01_11:     hex4_r = seg_r;
		8'b11_10_11_11:     hex5_r = seg_r;
		8'b11_01_11_11:     hex6_r = seg_r;
		8'b10_11_11_11:     hex7_r = seg_r;
		8'b01_11_11_11:     hex8_r = seg_r;
		default:            seg_r  = seg_r;
	endcase
end

// 将寄存器的值赋予输出端口
assign  hex1 = hex1_r;
assign  hex2 = hex2_r;
assign  hex3 = hex3_r;
assign  hex4 = hex4_r;
assign  hex5 = hex5_r;
assign  hex6 = hex6_r;
assign  hex7 = hex7_r;
assign  hex8 = hex8_r;

endmodule

三、实现过程

3.1 模块说明

这里要求超声波模块的正负极分别接入5V和GND,其余trigger和echo自由接线,我这里使用的是GPIO[0]和GPIO[1]

在这里插入图片描述

3.2 引脚分配

首先这里提出引脚配置,其中trig和echo引脚与自己所接线的位置向同即可在这里插入图片描述

三、演示视频

FPGA基于DE2-115开发板驱动HC_SR04超声波测距模块|集成蜂鸣器,led和vga提示功能


总结

本次测试借用了一些学长的代码,也带有自己的一些思考,补全了学长没有写进代码的部分。由于代码中设计的寄存器只有那么多位数,也和驱动本身的下限,决定了这次设计只能测试大概4~247cm左右的距离。能够自己补全一部分代码,对于我来说还是很有成就感的,下次见

参考

FPGA基于DE2-115 开发板板和HC_SR04驱动的超声波测距

基于DE2 115开发板驱动HC_SR04超声波测距模块

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣刷题--2085. 统计出现过一次的公共字符串【简单】

题目描述 给你两个字符串数组 words1 和 words2 &#xff0c;请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目。 示例 1&#xff1a; 输入&#xff1a;words1 [“leetcode”,“is”,“amazing”,“as”,“is”], words2 [“amazing”,“leetcode”,“is”] 输出…

万字详解 MySQL MGR 高可用集群搭建

文章目录 1、MGR 前置介绍1.1、什么是 MGR1.2、MGR 优点1.3、MGR 缺点1.4、MGR 适用场景 2、MySQL MGR 搭建流程2.1、环境准备2.2、搭建流程2.2.1、配置系统环境2.2.2、安装 MySQL2.2.3、配置启动 MySQL2.2.4、修改密码、设置主从同步2.2.5、安装 MGR 插件 3、MySQL MGR 故障转…

QT之动态加载树节点(QTreeWidget)

之前写过一篇动态加载ComboBox&#xff0c;可参见下面这篇文章 QT之动态加载下拉框&#xff08;QComboBox&#xff09; 同理QTreeWidget也可以实现动态加载&#xff0c;在一些异步加载数据&#xff0c;并且数据加载比较耗时&#xff0c;非常实用。 效果 原理分析 要实现此类效…

[数据集][图像分类]骨关节炎严重程度分类数据集14038张4分类

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;14038 分类类别数&#xff1a;4 类别名称:[“grade0”,“grade2”,“grade3…

如何使用KolorPanotourPro制作全景图像网页

目录 前言 KolorPanotourPro是什么 如何制作全景网页 1.拥有全景图 2.导入图片 3.在多张全景图中跳转 4.查看制作的全景网页 结束语 前言 今天是坚持写博客的第十五天&#xff0c;继续为努力和坚持的大家点赞和鼓掌。 书接上文&#xff0c;我们讲了如何使用如何使用A…

公园【百度之星】/图论+dijkstra

公园 图论dijkstra #include<bits/stdc.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pii; vector<ll> v[40005]; //a、b、c分别是小度、度度熊、终点到各个点的最短距离 ll a[40005],b[40005],c[40005],dist[40005],st[40005]; void…

1.1 OpenCV随手简记(一)

OpenCV学习篇 OpenCV (Open Source Computer Vision Library) 是一个开源的计算机视觉库&#xff0c;它提供了大量的算法和函数&#xff0c;用于图像处理、计算机视觉和机器学习等领域。 1. OpenCV 简介 1.1 OpenCV 的起源和发展 OpenCV 项目始于 1999 年&#xff0c;由 In…

IDeal下的SpringBoot项目部署

一、首先找到自己的sql文件&#xff0c;没有就从数据库挪进来 二、在Maven下打包一下&#xff08;点击package&#xff09;&#xff0c;看到BUILD SUCCESS就是打包好了 三、将上面两个文件分别挪到 linux 中对应的文件&#xff0c;没有就创建一个&#xff08;我的是spring_blog…

制作ChatPDF之Elasticsearch8.13.4搭建(一)

Elasticsearch8.x搭建 在Windows系统上本地安装Elasticsearch的详细步骤如下&#xff1a; 1. 下载Elasticsearch 访问 Elasticsearch下载页面。选择适用于Windows的版本8.13.4&#xff0c;并下载ZIP文件。 2. 解压文件 下载完成后&#xff0c;找到ZIP文件&#xff08;例如…

【2023百度之星初赛】跑步,夏日漫步,糖果促销,第五维度,公园,新材料,星际航行,蛋糕划分

目录 题目&#xff1a;跑步 思路&#xff1a; 题目&#xff1a;夏日漫步 思路&#xff1a; 题目&#xff1a;糖果促销 思路&#xff1a; 题目&#xff1a;第五维度 思路&#xff1a; 题目&#xff1a;公园 思路&#xff1a; 新材料 思路&#xff1a; 星际航行 思路…

网上蛋糕售卖店管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;店员管理&#xff0c;用户管理&#xff0c;商品管理&#xff0c;基础数据管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;公告信息&#xff0c;商品…

MFC 解决Enter回车键和Esc取消键默认关闭窗口的三种方法

文章目录 问题描述问题原因解决办法方法一&#xff1a;在重载的PreTranslateMessage 函数中屏蔽回车和ESC 的消息方法二&#xff1a;重载OnOK函数方法三&#xff1a;将所有按钮类型设为普通按钮&#xff0c;并设置其中一个按钮为默认按钮 问题描述 一般情况下编写的MFC对话框程…

【如何在日志中输出精确到毫秒的时间戳】

1. 需求 在日志中输出精确到毫秒级的时间戳&#xff0c; 格式为&#xff1a;%Y-%m-%d %H:%M:%S.%MS 如&#xff1a;2024-05-30 22:33:25.821 2. 代码实现 #include <iostream> #include <chrono> #include <iomanip> #include <sstream> #include &…

锻压设备智能制造工厂物联数字孪生平台,推进制造业数字化转型

锻压设备智能制造工厂物联数字孪生平台&#xff0c;推进制造业数字化转型。随着全球制造业的飞速发展&#xff0c;数字化转型已经成为企业提升竞争力、实现可持续发展的关键。在锻压设备智能制造领域&#xff0c;工业物联数字孪生平台以其强大的数据集成、分析和管理能力&#…

k均值过程图解

k均值聚类实际上是数据空间质心的Voronoi 划分问题。

C语言 | Leetcode C语言题解之第124题二叉树中的最大路径和

题目&#xff1a; 题解&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ int max; int dfs(struct TreeNode* root){if(!root) return 0;int left dfs(root->left…

中继器、集线器、网桥、交换机、路由器和网关

目录 前言一、中继器、集线器1.1 中继器1.2 集线器 二、网桥、交换机2.1 网桥2.2 交换机 三、路由器、网关3.1 路由器3.2 网关 总结 前言 理解这些设备的关键是他们运行在不同的层次上。之所以存在不同层的问题&#xff0c;是因为不同的设备使用不同的信息来决定如何交换。在典…

AI大模型的创新之道:突破局限与引领未来

1、引言 随着人工智能技术的飞速发展&#xff0c;AI大模型已成为推动科技进步的重要力量。它们不仅拥有强大的数据处理能力和学习能力&#xff0c;还能在多个领域展现出超越人类智慧的潜力。然而&#xff0c;AI大模型也面临着诸多挑战和局限&#xff0c;如数据依赖、计算资源消…

[数据集][目标检测]剪刀石头布检测数据集VOC+YOLO格式1973张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1973 标注数量(xml文件个数)&#xff1a;1973 标注数量(txt文件个数)&#xff1a;1973 标注…

【Qt】【模型视图架构】代理模型示例

文章目录 1. 基本排序/过滤模型Basic Sort/Filter Model Example2. 自定义排序/过滤模型Custom Sort/Filter Model ExampleFilterLineEdit类定义及实现MySortFilterProxyModel类定义及实现 1. 基本排序/过滤模型Basic Sort/Filter Model Example 官方提供的基本排序/过滤模型示…