学习STC51单片机13(芯片为STC89C52RC)

news2025/5/24 17:41:50

我去,兄弟们我们今天来学习一个牛逼 的硬件,它叫超声波测距模块HC—SR04

硬件:HC—SR04

哎,想当初最想要玩的就是这个模块,科技感十足,那现在就让我们玩玩吧

超声波测距传感器

原理就是说需要给Trig 10us的高电平,相当于是一个信号,到模块内部,模块内部有脉冲模块一直向着外部发送超声波,此时echo由低电平变成了高电平,然后如果有障碍物了,那么返回到echo里面会由高电平转换为低电平,计算的就是echo接收的第一个波到最后一个波,由高电平到最后一个波结束变成低电平的时间

        因为你可以拿  0001(1)  0010(2)  0100(3) 1000(4) 这个几个二进制数从1转换到4,你一个个转换会发现就是有这个规律 :二进制左移一位相当于x2的一次方  左移8位相当于左移2的8次方

超声波的时序图:(这也是我们第一次接触时序图)

这个是我们的最终代码,其中有很多的优化细节 都是为了测试硬件和提高稳定性的,所以有些代码不是功能的实现,而是细节的提升

#include "reg52.h"

#include <intrins.h>  // 包含_nop_()函数

sbit D5 = P3^7;     // 黄灯(距离<10cm时亮)

sbit D6 = P3^6;     // 蓝灯(距离≥10cm时亮)

sbit Trig = P1^5;   // 超声波触发引脚

sbit Echo = P1^6;   // 超声波接收引脚

// 精确延时函数

void Delay10us()    //@11.0592MHz

{

    _nop_(); _nop_(); _nop_(); _nop_(); _nop_();

    _nop_(); _nop_(); _nop_(); _nop_(); _nop_();

}

void Delay50ms()    //@11.0592MHz

{

    unsigned char i, j;

    i = 90;

    j = 163;

    do

    {

        while (--j);

    } while (--i);

}

void Delay100ms()   //@11.0592MHz

{

    unsigned char i, j;

    i = 183;

    j = 105;

    do

    {

        while (--j);

    } while (--i);

}

// 定时器0初始化(16位模式)

void Time0_Init()

{

    TMOD &= 0xF0;   // 清零T0模式位

    TMOD |= 0x01;   // 设置T0为模式1(16位定时器)

    TH0 = 0;        // 初始化计数寄存器

    TL0 = 0;

    TR0 = 0;        // 初始不启动定时器

}

// 触发超声波测距

void Trigger_HC_SR04()

{

    Trig = 0;

    _nop_();

    Trig = 1;       // 发送至少10μs的高电平触发信号

    Delay10us();

    Trig = 0;

}

// 主函数

void main()

{

    unsigned int Time;    // 超声波飞行时间(μs)

    unsigned int Distance;  // 距离(cm)

    unsigned int timeout;   // 超时计数器

    unsigned char i;        // 定义循环变量(解决编译错误)

    

    Time0_Init();           // 初始化定时器

    

    // 上电自检:LED交替闪烁3次

    for(i=0; i<3; i++) {    // 修正后的for循环

        D5 = 0; D6 = 1;     // 黄灯亮

        Delay100ms();

        D5 = 1; D6 = 0;     // 蓝灯亮

        Delay100ms();

    }

    

    // 默认状态:蓝灯亮(表示距离≥10cm)

    D5 = 1;

    D6 = 0;

    

    Delay100ms();          // 等待传感器稳定

    

    while(1)

    {

        // 确保Echo初始为低电平(否则可能是传感器异常)

        if(Echo == 1) {

            D5 = 1; D6 = 1;  // 双灯亮表示异常

            Delay100ms();

            continue;

        }

        

        // 触发测距

        Trigger_HC_SR04();

        

        // 等待Echo变高(添加超时:约10ms)

        timeout = 10000;

        while(Echo == 0 && --timeout);

        if(timeout == 0) {

            D5 = 1; D6 = 1;  // 超时错误:双灯亮

            Delay50ms();

            continue;

        }

        

        // 启动定时器

        TH0 = 0;

        TL0 = 0;

        TR0 = 1;

        

        // 等待Echo变低

        timeout = 65535;

        while(Echo == 1 && --timeout);

        TR0 = 0;

        

        // 计算距离(仅在未超时的情况下)

        if(timeout != 0) {

            // 计算时间(晶振补偿:11.0592MHz需要乘以1.085)

            Time = (TH0 * 256 + TL0) * 1.085;

            

            // 计算距离(单位:cm)

            Distance = Time * 17 / 1000;  // 等价于Time * 0.017

            

            // 根据距离控制LED

            if(Distance < 10) {  //如果 timeout 没有减到 0(即 Echo 信号在超时之前成功从高电平变回低电平)

                 D5 = 0; D6 = 1;  // 蓝灯亮:距离大于小于10cm

            } else {

 D5 = 1; D6 = 0;  // 黄灯亮:距离大于10cm

                          }

        } else {

            D5 = 1; D6 = 1;  // 超时错误:双灯亮

        }

        

        Delay50ms();  // 测量间隔,避免频繁触发  手册规定两次间隔至少60ms(哎我这边写50也无所谓的)

    }

}

当然我这个是优化过了的代码,因为之前的代码不稳定,容易实现不了功能你们可以拿去试试水

旧代码

这个代码有几点 需要重要解释的就是计算

首先时间的计算,本质就是计算echo的高电平到低电平的时间

那么我们定时器的TH0 和TL0 是发挥作用的,因为他们记录了次数,每次是1.085us,因为晶振的频率是11.059Mhz,我们定时器的模式又是16位,所以我们又要知道TH0和TL0是8位寄存器,高八位给TH0,低八位给TL0,记录的都是次数,我们将低八位让给TL0  其实就是这个效果啦

10101011  要变成1010101100000000(这个是一个二进制格式),那么我们该怎么办呢其实就是用到了这个方法

二进制左移一位相当于x2的一次方  左移8位相当于左移2的8次方

你看这个图就非常明显了,DEC是十进制这个数为65535是2的16次方,也就是16位2进制能有多少种搭配个数,那我们这个 前面8位数TH0的位置  后面8位数TL0的位置,所以我们可以根据这个信息来获取次数,我们通过二进制的数据来转换成10进制的次数,那么这个次数就可以与每次1.085us进行相乘得出总的时间

还有一个要注意的是距离的计算,有个公式叫做距离=速度 x 时间 但是由于我们这个超声波的话是这样的,时间多付出一倍,所以距离要/2的,一来一回

声音的速度为340m/s 

随后根据公式就可以算出距离了。

最后我们来一些Tips:

对于第一个timeout设置为10ms是为什么?????

10ms 就是一个“兼顾大家”的折中值​​,既不过短(避免误判),也不过长(避免卡死),属于​​经验性参数​​。它的合理性可以从这几个角度理解

1. ​​“大家”是谁?​

  • ​硬件层面​​:超声波模块(如 HC-SR04)的典型响应时间在 ​​微秒级到几毫秒​​(例如,测距 1 米时,Echo 变高延迟约 5.8ms,但实际传感器内部电路响应可能更快)。
  • ​软件层面​​:嵌入式系统通常需要 ​​快速失败​​(避免因硬件故障导致整个系统僵死)。
  • ​用户体验​​:10ms 对人类来说几乎无感(LED 报错时用户不会觉得“卡顿”)。

就是Trig高电平进去之后,我们这个就要进行判断了,因为:超声波模块(如 HC-SR04)的典型响应时间在 ​​微秒级到几毫秒​

所以

  • 只要 Echo 仍然为 0(低电平)​​并且​​ timeout 自减后仍不为 0,就继续循环。
  • 如果 Echo 变为 1(高电平)​​或者​​ timeout 减到 0,循环终止。

Echo 高电平的持续时间(从第一个有效回波触发变高,到最后一个回波处理完毕变低)直接对应超声波往返的时间​而这个时间可以用来计算距离

这段代码有点意思:

 timeout = 65535;

        while(Echo == 1 && --timeout);

        TR0 = 0;

  • 如果 Echo 正常变低(测距完成),循环退出。
  • 如果 Echo 因硬件故障一直保持高电平,timeout 会递减至 0,强制退出循环(避免死等)。

​4. 为什么 timeout 初始值设为 65535?​

  • ​65535(0xFFFF)是 16 位无符号整数的最大值​​,确保超时时间足够长(约 71ms @11.095MHz 51单片机)。
  • ​覆盖最大测距​​:
    • HC-SR04 最大测距约 5 米,对应 Echo 高电平时间 ≈ 29ms(580µs/cm × 500cm)。
    • 设置 timeout = 65535 可确保即使测最远距离也不会误触发超时。

5米最大测距​​ = 硬件限制(Echo 最大 29ms) + 声波衰减。

3. 实例验证​

​场景1:正常测距(Echo 按预期变低)​
  • Echo 从 1 → 0(耗时 5ms),timeout 从 65535 减到 60000(未到 0)。
  • ​结果​​:timeout != 0 → 进入 if 分支,计算距离。
​场景2:超时异常(Echo 保持高电平)​
  • Echo 始终为 1timeout 从 65535 递减至 0(耗时约 65ms)。
  • ​结果​​:timeout == 0 → 进入 else 分支,双灯亮报错。
​场景3:干扰导致 Echo 异常变低​
  • Echo 因干扰短暂变低,但 timeout 未减到 0(如剩余 10000)。
  • ​结果​​:timeout != 0 → 仍进入 if 分支,但计算的距离可能无效(需软件滤波处理)。

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

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

相关文章

Claude 4 系列 Opus 4 与 Sonnet 4正式发布:Claude 4新特性都有哪些?

随着 Claude 4 系列&#xff08;Opus 4 与 Sonnet 4&#xff09;的正式发布&#xff0c;Anthropic 把自家大模型从“会聊天”推进到“能当自主代理”──不仅推理更深、上下文更长&#xff0c;还内置代码执行、多模态理解、工具调用等一揽子全新能力&#xff1b;同时&#xff0…

深度“求索”:DeepSeek+Dify构建个人知识库

目录 前言 环境部署 安装Docker 安装Dify 配置Dify 部署知识库 创建应用 前言 在当今数字化信息爆炸的时代&#xff0c;数据隐私和个性化知识管理成为企业和个人关注的焦点。Dify&#xff0c;作为一款备受瞩目的开源 AI 应用开发平台&#xff0c;为用户提供了完整的私有…

基于R语言的空间异质性数据分析技术

在自然和社会科学领域&#xff0c;存在大量与地理或空间相关的数据&#xff0c;这些数据通常具有显著的空间异质性。传统的统计学方法在处理这类数据时往往力不从心。基于R语言的一系列空间异质性数据分析方法&#xff0c;如地理加权回归&#xff08;GWR&#xff09;、地理加权…

网络学习-TCP协议(七)

一、TCP协议 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议。 1、三次握手 客户端&#xff1a; 1、先发起连接&#xff0c;发送SYN置1&#xff0c;seqnum12345(随机值)----半连接…

基于微信小程序的高校校园微活动管理系统设计与实现(源码+定制+开发)高校微信小程序校园活动发布与互动平台开发 面向大学生群体的校园活动移动平台设计与实现

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

云计算与大数据进阶 | 27、存储系统如何突破容量天花板?可扩展架构的核心技术与实践—— 分布式、弹性扩展、高可用的底层逻辑(上)

数据中心里&#xff0c;存储系统是至关重要的组成部分。由于相关硬件组件与存储操作系统的多样性和复杂性&#xff0c;如何在保证存储稳定、安全、可靠的同时&#xff0c;实现灵活扩展和自服务&#xff0c;一直是困扰数据中心全面云化的难题。 简单来说&#xff0c;现在的难题…

IvorySQL-WASM:免安装的数据库探索之旅

简介 为了降低社区用户的使用门槛&#xff0c;提升使用体验&#xff0c;IvorySQL 社区特别推出了 IvorySQL-WASM 项目&#xff0c;帮助用户快速在线 Demo。 IvorySQL-WASM 基于开源的 Postgres-WASM 框架开发。它允许用户直接在网页浏览器中体验 IvorySQL&#xff0c;无需本地…

飞牛fnNAS远程映射盘符

目录 一、NAS、PC端配置Zerotier 二、使用网上邻居 三、使用WebDAV 1.开启WebDAV 2.PC上安装RaiDrive并设置 如果能将NAS作为本机一个盘符来使用,一定会令我非常方便。如果是本地,可以很方便实现。 将飞牛NAS映射为本地盘符,常用两种方式,一种是网上邻居,另一种是We…

Java设计模式:探索编程背后的哲学

设计模式是软件开发中的一种常见方法&#xff0c;它为常见问题提供了解决方案。在Java世界中&#xff0c;设计模式的应用尤为广泛。本文将深入探讨Java设计模式的起源、分类和实际应用&#xff0c;帮助读者更好地理解和应用这些模式。设计模式不仅是编程的技术&#xff0c;更是…

Docker部署OpenSearch集群

OpenSearch 简介 OpenSearch 是一款开源的搜索与分析引擎&#xff0c;最初由亚马逊 AWS 开发&#xff0c;于 2021 年 9 月将其移交至 Linux 基金会旗下的 OpenSearch 软件基金会&#xff0c;此后实现了社区主导的治理模式。其具有高性能、可扩展性强、兼容性强等优点&#xff…

【AS32X601驱动系列教程】PLIC_中断应用详解

平台中断控制器&#xff08;Platform Level Interrupt Controller&#xff0c;PLIC&#xff09;是国科安芯AS32系列MCU芯片的中断控制器&#xff0c;主要对中断源进行采样&#xff0c;优先级仲裁和分发。各外设中断统一连到PLIC&#xff0c;PLIC统一管理并输出中断请求到内核。…

python学习打卡day34

DAY 34 GPU训练及类的call方法 知识点回归&#xff1a; CPU性能的查看&#xff1a;看架构代际、核心数、线程数GPU性能的查看&#xff1a;看显存、看级别、看架构代际GPU训练的方法&#xff1a;数据和模型移动到GPU device上类的call方法&#xff1a;为什么定义前向传播时可以直…

leetcode-快慢指针系列

开胃小菜 141. 环形链表 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链…

JAVA05基本数据类型和包装类的转换,转换成其他数据类型,包装类与字符串的转换+学生类的定义实例

1.基本数据类型和包装类的转换 下面是一个自动手动的例题 2.将包装类转换成其他类型 3. 将数据类型转换成字符串 将字符串转换成数据类型 以下是一个例题 学生类的例题

Python打卡训练营学习记录Day34

知识点回归&#xff1a; CPU性能的查看&#xff1a;看架构代际、核心数、线程数 GPU性能的查看&#xff1a;看显存、看级别、看架构代际 GPU训练的方法&#xff1a;数据和模型移动到GPU device上 类的call方法&#xff1a;为什么定义前向传播时可以直接写作self.fc1(x) CPU性…

动手学习深度学习V1.1 chapter2 (2.1-2.2)

chapter2&#xff1a;深度学习基础 区分问题&#xff1a;回归问题还是分类问题&#xff1f; 输出结果是不明确的连续值的时候就是回归问题&#xff0c;比如房价预测&#xff0c;销售额预测等。 输出结果是明确几个离散值的时候就是分类问题&#xff0c;比如字符识别&#xf…

数据结构(6)线性表-队列

一、队列的概述 队列也是一种特殊的线性表&#xff0c;只允许在一段插入数据&#xff0c;另一端删除数据。插入操作的一端称为队尾&#xff0c;删除操作的一端称为队头。 如图&#xff1a; 二、队列相关操作 1.队列结构体的声明 类似于栈&#xff0c;他肯定也得借助于数组或…

【数据架构04】数据湖架构篇

✅ 10张高质量数据治理架构图 无论你是数据架构师、治理专家&#xff0c;还是数字化转型负责人&#xff0c;这份资料库都能为你提供体系化参考&#xff0c;高效解决“架构设计难、流程不清、平台搭建慢”的痛点&#xff01; &#x1f31f;限时推荐&#xff0c;速速收藏&#…

uniapp-商城-62-后台 商品列表(分类展示商品的布局)

每一个商品都有类别&#xff0c;比如水果&#xff0c;蔬菜&#xff0c;肉&#xff0c;粮油等等&#xff0c;另外每一个商品都有自己的属性&#xff0c;这些都在前面的章节进行了大量篇幅的介绍。这里我们终于完成了商品类的添加&#xff0c;商品的添加&#xff0c;现在到了该进…

初识C++:模版

本篇博客主要讲解C模版的相关内容。 目录 1.泛型编程 2.函数模板 2.1 函数模版概念 2.2 函数模版格式 2.3 函数模版的原理 2.4 函数模版的实例化 1.隐式实例化&#xff1a;让编译器根据实参推演模板参数的实际类型 2. 显式实例化&#xff1a;在函数名后的<>中指定模…