基于MAX-10 FPGA 读取超声波模块HC_SR04距离数据到数码管上

news2024/10/2 16:28:40

目录

    • 实验现象
    • 简单介绍超声波测距模块HC_SR04
    • 模块框图
    • 模块编写
      • 测距信号源
      • 距离计算
      • 数码管模块
      • 顶层模块
    • 总结

实验现象

将MAX-10小脚丫FPGA和超声波模块HC_SR04插在面包板上,用杜邦线将对应的引脚连接好,烧录程序,小脚丫自带的数码管显示距离数据(单位是厘米)。
4CM18CM这张图拍花了,数码管显示的数据是18CM

简单介绍超声波测距模块HC_SR04

HC-SR04是一种基于超声波的测距模块。该模块向前15度内发送超声波并接收回响,通过发出超声波到收到回响的这个时间间隔计算前方的障碍物距离,可以用来给智能小车做障碍物监测。可提供2cm- 400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超声波发射器、接收器与控制电路。

该模块的时序图如下:

在这里插入图片描述该模块的引脚图如下:
在这里插入图片描述
我们在编写代码的时候,想要发出测距命令,需要先保持触发信号输入(trig引脚)为低电平,然后保持大于10us的高电平,再变成低电平即可(时序图第一行所示)。

发出测距命令后,回响信号输出(echo引脚)会保持一段时间的高电平,这个高电平的持续时间与距离有关。我们在FPGA编写代码测量高电平持续时间,然后将时间转化为距离即可。

经过测试,得到以下结论:
1、发送测距的时候,每个脉冲之间的间隔不要过近,我用的间隔是300ms,即每300ms测一次距离,也可以根据需要修改。
2、接收端高电平时间与距离的关系式是:距离(cm)= 高电平持续时间(us)x 0.034cm / 2 (除以2是因为持续时间是往返时间,除以2才是单程时间)

模块框图

我们需要设计以下模块:
1、测距信号源模块,输入时钟与复位,每隔300ms输出15us高电平。

2、距离计算模块,输入时钟、复位与回响信号echo,输出距离(cm)

3、数据显示模块,将得到的距离可视化,我用的是2个1位数码管模块(小脚丫自带两个1位共阴极数码管)

4、顶层模块

框图如下:

在这里插入图片描述

模块编写

测距信号源

在此模块,写一个计时周期为300us的循环计数器,当计数器值小于15时输出高电平,其他时候输出低电平即可。
代码如下:

module trigger_send #(
    parameter TIME_1S = 12_000_000
) (
    input   clk ,
    input   rst_n   ,
    output  trigger
);

//1us生成
wire clk_1us;
PLL UPLL(
	.inclk0 (clk),
	.c0 (clk_1us)
);

reg [25:0] cnt_1us;
always @(posedge clk_1us or negedge rst_n) begin
    if (!rst_n) begin
        cnt_1us <= 20'd0;
    end
    else if (cnt_1us == 20'd300_000 - 1)begin
        cnt_1us <= 20'd0;
    end
	 else begin
        cnt_1us <= cnt_1us + 1'b1;
    end
end

assign trigger = cnt_1us < 15 ? 1'b1 : 1'b0;

endmodule

我懒得自己写1us的计数器,用锁相环生成了一个1MHZ(1us)的时钟,让它驱动计时,你可以不用锁相环自己写1us比特计数,不知道怎么用锁相环可以搜一下,很简单。

距离计算

这个模块输入了HC_SR04的回响引脚,要做的就是计算它的高电平持续时间,并转化为距离数据输出。

这里持续时间的单位用us最合适,因此同样生成一个1us时钟,用这个时钟监测回响信号的上升沿与下降沿。检测到上升沿,就每过一个时钟周期就把计时器数值加1(可以自己设置上限,表示最大检测距离);等检测到下降沿,就把计时器的数据保存起来,然后把计时器清空准备下次计时。

拿到保存好的计时后,使用上文提到的公式计算出距离输出。

代码如下:

module data_rec #(
    parameter TIME_1S = 12_000_000
) (
    input   clk ,//系统时钟
    input   rst_n   ,//复位
    input   rec_data    ,//回响,早知道取名echo了
    output  [11:0] distance	//计算好的距离
);
//锁相环生成1us周期时钟,因为后面的计时单位全是1us,这样方便
wire clk_1us;
PLL UPLL(
	.inclk0 (clk),
	.c0 (clk_1us)
);

//给回响信号打拍,检测上升沿下降沿
reg rec_data2;
reg rec_data3;
wire rec_negedge;
wire rec_posedge;
assign rec_negedge = (!rec_data2) && rec_data3;
assign rec_posedge = rec_data2 && (!rec_data3);
always @(posedge clk_1us or negedge rst_n) begin
    if (!rst_n) begin
        rec_data2 <= 1'b0;
    end
    else begin
        rec_data2 <= rec_data;
    end
end
always @(posedge clk_1us or negedge rst_n) begin
    if (!rst_n) begin
        rec_data3 <= 1'b0;
    end
    else begin
        rec_data3 <= rec_data2;
    end
end

//计时启动标志,上升沿启动,下降沿结束
reg flag;
always @(posedge clk_1us or negedge rst_n) begin
    if (!rst_n) begin
        flag <= 1'b0;
    end
    else if (rec_posedge)begin
        flag <= 1'b1;
    end
    else if (rec_negedge)begin
        flag <= 1'b0;
    end
    else begin
        flag <= flag;
    end
end

//计时器数值,flag期间计数,有下降沿就清0,急了多少数就是保持了多少us,因为是用1us时钟驱动的
reg [14:0] cnt_1us;
always @(posedge clk_1us or negedge rst_n) begin
    if (!rst_n) begin
        cnt_1us <= 15'd0;
    end
    else if (rec_negedge)begin
        cnt_1us <= 15'd0;
    end
    else if (flag && cnt_1us < 15'd15_000)begin
        cnt_1us <= cnt_1us + 1'b1;
    end
    else begin
        cnt_1us <= cnt_1us;
    end
end

//因为计时器结束计时会变0,因此要用另外的变量,在它清0的时候把值保存下来
reg [14:0] high_time;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        high_time <= 15'd0;
    end
    else if (rec_negedge)begin
        high_time <= cnt_1us ;
    end
    else begin
        high_time <= high_time;
    end
end

//计算距离,Verilog不能直接用浮点数,就这样实现乘以0.017
//为什么不是0.034看前面
reg [11:0] distance_buf;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        distance_buf <= 12'd0;
    end
    else begin
        distance_buf <= high_time * 17 / 1000;
    end
end
assign distance = distance_buf;

endmodule

数码管模块

距离模块的distance就是测到的距离,你拿去数码管输出,串口打印都可以。我的小脚丫自带两个1位的共阴极数码管,就用它们来显示,毕竟自己在面包板上给数码管插线插电阻还是挺麻烦的。

用的时候取出测的距离的十位个位分别给两个模块就行。

1位七段式共阴极数码管十进制显示模块如下:

module nixietube_1 (
    input   clk,
    input   rst_n,
    input   [3:0]   din, //输入0-9
    output  drive_out, //使能
    output  [6:0]   _dig, //输出数码管
    output  dot_out //小数点要亮吗
);
//dot小数点输出
assign dot_out = 1'b0;

//使能,阴极为0
assign drive_out = 1'b0;

//dig段选输出
parameter   ZER = 7'b0111111,
            ONE = 7'b0000110,
            TWO = 7'b1011011,
            THR = 7'b1001111,
            FOU = 7'b1100110,
            FIV = 7'b1101101,
            SIX = 7'b1111101,
            SEV = 7'b0000111,
            EIG = 7'b1111111,
            NIN = 7'b1101111;
            
reg [6:0]   dig;

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        dig <= ZER;
    end
    else begin
        case (din)
            0 : dig <= ZER;
            1 : dig <= ONE;
            2 : dig <= TWO;
            3 : dig <= THR;
            4 : dig <= FOU;
            5 : dig <= FIV;
            6 : dig <= SIX;
            7 : dig <= SEV;
            8 : dig <= EIG;
            9 : dig <= NIN;
            default : dig <= ZER;
        endcase
    end
end

assign _dig = dig;

endmodule

顶层模块

连起来就可以了,没什么好说的。

module Ultrasound  (
    input   clk,
    input   rst_n,
    input   rec_data    ,
    output  trigger ,
    output  [6:0]   dig1,
	 output  [6:0]   dig2,
    output  dot1,
	 output  dot2,
	 output  drive1,
	 output  drive2
); 
    trigger_send u_trigger_send(
        .clk (clk),
        .rst_n (rst_n),
        .trigger (trigger)
    );

    wire [11:0] distance;
    data_rec u_data_rec(
        .clk (clk),
        .rst_n (rst_n),
        .rec_data (rec_data),
        .distance (distance)
    );
		
	 nixietube_1 u_nixietube_1(
        .clk (clk),
        .rst_n (rst_n),
        .din    ((distance/10)%10),
        ._dig (dig1),
        .dot_out (dot1),
		  .drive_out (drive1)
    );
	 
	 nixietube_1 u_nixietube_2(
        .clk (clk),
        .rst_n (rst_n),
        .din    ((distance/1)%10),
        ._dig (dig2),
        .dot_out (dot2),
		  .drive_out (drive2)
    );

endmodule  

引脚设置的时候,两个数码管,时钟按照小脚丫的原理图来设置,trig与echo自己设置,复位键可以用它自带的按钮。

总结

本次实验实现了使用FPGA驱动超声波模块HC_SR04,以前在小车比赛见过,但当时用的官方提供好的示例代码。现在自己也知道如何使用了,可以拿去做很多东西,收获很大。

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

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

相关文章

全网火爆,性能测试面试常问+测试小技巧总结,要卷就卷成最强的...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试面试常问…

itop-3568开发板驱动学习笔记(26)设备树(五)中断实例分析

《【北京迅为】itop-3568开发板驱动开发指南.pdf》 学习笔记 文章目录 中断控制器配置中断其他属性 中断控制器 设备树中的中断控制器节点和 GPIO 控制器类似&#xff0c;都是由芯片厂家编写&#xff0c;如果是外部中断&#xff0c;中断控制器和 GPIO 控制器是共存的&#xff…

TDengine “亮相” ODSC East,开发者争相驻足交流

最近 TDengine 终于将时序数据技术创新这把火 烧到了美国波士顿 并获得了一众国外开发者的热捧 而这一次 TDengine 的成功落地 还得从两天前的一场数据大会说起... 波士顿当地时间 5 月 9 日&#xff0c;一场名为 ODSC East 的数据技术盛会在波士顿缓缓拉开序幕&#xff0…

YOLO V1-V3 简单介绍

目录 1. YOLO 2. YOLO V1 3. YOLO V2 4. YOLO V3 5. YOLO V3 SPP网络 5.1 Mosaic 图像增强 5.2 SPP 模块 5.3 CIou Loss 5.4 Focal loss 1. YOLO YOLO 是目标检测任务强大的算法&#xff0c;将目标检测的问题转换边界框和相关概率的回归问题&#xff0c;是目标检测…

【JAVA应届生如何提高职场竞争力】从蓝海走向红海的IT世界,新人如何掌握IT技能和找到合适的工作

从蓝海走向红海的IT世界,新人如何掌握IT技能和找到合适的工作。 在当前就业形势下,如何提高应届生在职场中的竞争力?具有哪些有效的方法和策略可供选择?这是一个备受关注的热点话题。哪些方面会对应届生的职场发展起到关键的推动和支撑作用呢? 前段时间有位CSDN的…

更高效便捷的开发体验——Cloud Studio 编辑器命令行工具

Cloud Studio 是一个云端在线开发平台&#xff0c;在 Cloud Studio 的控制台页面中&#xff0c;可以方便快捷创建或者打开一个工作空间。工作空间提供了在线编辑器给大家访问远端开发环境。大部分开发时间都与这个在线编辑器打交道&#xff0c;在线编辑器效果如下图所示&#x…

【刷题之路】LeetCode232——用栈实现队列

一、题目描述 原题链接&#xff1a;https://leetcode.cn/problems/implement-queue-using-stacks/ 题目描述&#xff1a; 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类…

深拷贝/浅拷贝精讲

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

Java 中Spring Security 是什么?如何使用

简介 Spring Security是一款基于Spring框架的安全框架&#xff0c;它提供了一系列的功能和API&#xff0c;用于保护Web应用程序和REST API的安全性。Spring Security可以提供身份验证、授权、加密和防止攻击等功能。它是Spring框架的一部分&#xff0c;可以与Spring框架无缝集…

Redis3种特殊数据结构详解

1、Bitmap位存储 Bitmap存储的是连续的二进制数字&#xff08;0和1&#xff09;。 你可以将Bitmap看作是一个存储二进制数字&#xff08;0和1&#xff09;的数组&#xff0c;数组中每个元素的下标叫做offset&#xff08;偏移量&#xff09;。 应用场景&#xff0c;需要保存状态…

​Cloud Studio 云端开发保障企业源代码安全

为什么需要保证 企业源代码安全 随着时代的发展&#xff0c;各行各业的企业或多或少都会与软件源代码打交道&#xff0c;借助软件系统更好地提升企业办公效率&#xff0c;而软件的源代码也自然成了一种企业新型资产。如何确保企业源代码不外泄&#xff0c;成为了各个企业特别关…

scau 拓扑排序

18734 拓扑排序 时间限制:1000MS 代码长度限制:10KB 提交次数:0 通过次数:0 题型: 编程题 语言: G;GCC Description 在经历.....之后&#xff0c;你打算好好学习下计算机专业的课程&#xff0c;避免面试过程中的各种尴尬场面。 计算机的专业课程间既有循序渐进的特点&…

解决方案 自动测试平台 通用测试平台

“通用测试平台”是针对测试保障所需研制的小型化、通用化、平台化综合保障设备。它采用可灵活扩展、剪裁和重构的开放式体系结构&#xff0c;支持用户对测试资源进行快速地剪裁或扩展&#xff0c;结合功能强大灵活的软件平台&#xff0c;能够支持多种被测件的测试和故障诊断。…

电赛E题声源定位跟踪系统制作全过程

声源定位 文章目录 声源定位前言一、题目二、设计步骤1.设计思路2.声源追踪定位的分析3.舵机转角的确定4.声源距离的计算 三、代码编写1.求均值2.卡尔曼滤波 复刻一下电赛的声源定位 前言 2023年的电子设计竞赛快要开始了&#xff0c;同时我也已经大三下了正在准备找工作&…

Mybatis之配置解析

目录 核心配置文件 environments&#xff08;环境配置&#xff09; properties&#xff08;属性&#xff09; typeAliases( 类型别名) 映射器 注解开发 Mybatis执行流程 核心配置文件 mybatis-config.xml configuration&#xff08;配置&#xff09; pr…

【STM32】STM32使用RFID读卡器

STM32使用RFID读卡器 RFID卡片 ID卡&#xff08;身份标识&#xff09;&#xff1a;作用就是比如你要输入学号&#xff0c;你刷卡直接就相当于输入学号&#xff0c;省去了输入的过程 IC卡&#xff1a;集成电路卡&#xff0c;是将一种微电子芯片嵌入卡片之中 RFID的操作 1、…

【C++学习】模板初阶

目录 一、泛型编程 二、函数模板 2.1 函数模板概念 2.2 函数模板格式 2.3 函数模板的原理 2.4 函数模板的实例化 2.5 模板参数的匹配原则 三、类模板 3.1 类模板的定义格式 3.2 类模板的实例化 一、泛型编程 我们前面学习了C的函数重载功能&#xff0c;那么我们如何实现…

低调的接口工具 ApiKit

最近发现一款接口测试工具--ApiKit&#xff0c;我们很难将它描述为一款接口管理工具 或 接口自测试工具。 官方给了一个简单的说明&#xff0c;更能说明 Apikit 可以做什么。 ApiKit API 管理 Mock 自动化测试 异常监控 团队协作 ApiKit的特点&#xff1a; 接口文档定义&a…

多层级缓存

多级缓存 多级缓存方案 多级缓存就是充分利用请求处理的每个环节&#xff0c;分别添加缓存&#xff0c;减轻Tomcat压力&#xff0c;提升服务器性能&#xff1a; 用作缓存的Nginx是业务Nginx&#xff0c;需要部署为集群&#xff0c;再有专门的Nginx用来做反向代理&#xff1a;…

ModStartCMS v6.4.0 模块市场升级,UI界面优化

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用&#xff0c;支持后台一键快速安装&#xff0c;让开发者能快的实现业务功能开发。 系统完全开源&#xff0c;基于 Apache 2.0 开源协议&#xff0c;免费且不限制商业使用。 功能特性 丰富的模块市…