请点击:B站视频链接

若打不开复制BV码到bilibili搜索即可:BV1KY5u6kEoh

大家好,在嵌入式开发中,非接触式距离检测是智能小车和避障系统里的核心感知技术。今天,我将结合 TI C2000 系列的 F28027 微控制器,带大家从底层硬件逻辑到应用层代码,完整、深入地拆解 HC-SR04 超声波测距模块的实现过程。


一、 核心硬件知识点:HC-SR04 是如何工作的?

HC-SR04 是一款采用集成化设计的经典模块,它的测距性能直接决定了系统的精度与响应速度。

1. 内部四大核心部件

该模块并不只是简单的发声器,它的内部协同完成了“电信号 - 超声波信号 - 电信号”的转换与距离计算触发:

  • 超声发射换能器:内部装有压电陶瓷振子,当接收到驱动电路输出的 40kHz 电信号时,会振动产生方向性强、抗干扰的 40kHz 超声波。

  • 超声接收换能器:与发射端配对,当捕捉到反射回来的超声波时,会将机械振动重新转化为微弱的电信号。

  • 内部驱动与调理电路:集成了信号放大、滤波和比较器功能,直接输出数字电平,大大简化了我们的硬件设计压力。

  • 控制逻辑单元:负责响应外部的触发信号,启动内部计时并在接收到回声后停止计时,最后通过 Echo 引脚输出高电平信号。

2. 引脚定义与回声定位逻辑

HC-SR04 有四个引脚:VCC(电源正极)、GND(电源地)、Trig(触发信号输入)、Echo(回响信号输出)。

VCC

电源正极

GND

电源地

Trig

触发信号输入

Echo

回响信号输出

它的核心逻辑可以概括为 “触发 - 发射 - 接收 - 计时” 四步:

  1. 触发:F28027 向 Trig 引脚输出一段持续时间 ≥ 10us 的高电平脉冲。

  2. 发射:模块响应触发信号,内部驱动电路自动生成 8 个连续的 40kHz 高频脉冲并通过探头(压电陶瓷振子)激发出超声波。

  3. 接收与计时:
    在超声波脱离探头飞入空气的瞬间,模块立刻将 Echo 引脚拉为高电平;此时 F28027 的 eCAP 模块检测到上升沿,同步启动定时器开始计秒表。

    超声波在空气中传播,遇到障碍物后反射形成回声。当模块的接收探头真正捕获到反射回来的超声波时,内部电路会瞬间将 Echo 引脚拉为低电平;F28027 检测到下降沿,立刻停止计时。

  4. 计算:Echo 引脚维持高电平的持续时间就是超声波往返的时间。如果 30ms 内未收到回声(超出 400cm 检测范围),Echo 也会降为低电平,表示超限。

距离计算核心公式:

测试距离 = (高电平时间 * 声速(340m/s)) / 2


二、 硬件接口与 eCAP 捕获模块原理

在信号流向上,整个系统遵循:单片机控制 → 接口传输 → 模块内部处理 → 信号反馈。

  • 硬件连接:HC-SR04 的 Trig 接口连接到 F28027 的 GPIO18 引脚(配置为输出模式)。

  • 信号反馈:Echo 接口连接到 F28027 的 GPIO19 引脚(配置为输入模式)。

硬件

硬件引脚

单片机引脚

引脚功能

超声波

ECHO_MCU

GPIO19

ECAP1

TRIG_MCU

GPIO18

GPIO18

要精准测量 Echo 的高电平时间,我们需要用到 C2000 的 捕获模块(Capture Module, eCAP)。

捕获模块能够精准检测输入信号的特定边沿(上升沿或下降沿)。当目标边沿到来时,硬件会自动锁存时间戳计数器(TSCTR)的当前值。通过计算上升沿和下降沿两次捕获值的差值,就能得到高电平的精确时间。


三、 代码逐行深度解析

接下来,我们将进入应用最核心的部分——代码实现。我将带大家逐行拆解驱动层的配置。

1. 引脚模式与方向配置 (Ultrasound_pinConfigure)

在这个函数中,我们要把 GPIO18 配置为普通的推挽输出,把 GPIO19 配置为 eCAP1 捕获输入。

void Ultrasound_pinConfigure(void)
{
    // 1. 设置 GPIO 工作模式:GPIO18 作为通用 I/O,GPIO19 复用为 ECAP1 功能
    GPIO_setMode(myGpio, GPIO_Number_18, GPIO_18_Mode_GeneralPurpose);
    GPIO_setMode(myGpio, GPIO_Number_19, GPIO_19_Mode_ECAP1);

    // 2. 禁用上拉电阻:由于外部模块已有明确电平,禁用内部上拉防止干扰
    GPIO_setPullUp(myGpio, GPIO_Number_18, GPIO_PullUp_Disable);
    GPIO_setPullUp(myGpio, GPIO_Number_19, GPIO_PullUp_Disable);

    // 3. 设置方向:GPIO18 负责输出触发信号(Output),GPIO19 负责接收回声信号(Input)
    GPIO_setDirection(myGpio, GPIO_Number_18, GPIO_Direction_Output);
    GPIO_setDirection(myGpio, GPIO_Number_19, GPIO_Direction_Input);

    // 4. 输入质量配置:针对 GPIO19,配置为异步输入 (ASync),绕过采样同步逻辑,保证捕获时间的最高精度
    GPIO_setQualification(myGpio, GPIO_Number_19, GPIO_Qual_ASync);
}

        对于 GPIO_setQualification(myGpio, GPIO_Number_19, GPIO_Qual_ASync);

为什么极高精度测量必须用 ASync(异步模式)?

typedef enum
{
    GPIO_Qual_Sync = 0,      
//!< Denotes input will be synchronized to SYSCLK 输入信号将与系统时钟(SYSCLK)同步。
    GPIO_Qual_Sample_3,      
//!< Denotes input is qualified with 3 samples  3次采样滤波
    GPIO_Qual_Sample_6,      
//!< Denotes input is qualified with 6 samples
    GPIO_Qual_ASync         
 //!< Denotes input is asynchronous  异步模式
} GPIO_Qual_e;

当超声波的 Echo 信号引脚发生电平跳变(比如从低变高)时,这个信号就相当于一个要进站上车的“乘客”。

  • 如果配置为 Sync(同步模式):

    引脚内部有 D 触发器(类似于检票闸机)。当外部电平跳变时,这个信号不能直接跑进单片机内部,它必须等待下一个系统时钟的上升沿(下一班地铁到来),才能被“载入”到内部总线上。这意味着,哪怕外部信号是绝对精准的,单片机内部看到的信号也会产生 0 ~ 16.67ns(60Mhz主频) 不等的随机时间差。

  • 如果配置为 ASync(异步模式):

    相当于给这个信号开了一条VIP 物理直达通道。信号一到达引脚,完全不经过时钟同步闸机,直接以纯硬件电气连接的方式,瞬间怼到 eCAP 捕获模块的输入端。这就消除了那 1~2 个时钟周期的随机同步等待误差,确保时间戳计数器(TSCTR)锁存的是最真实的物理时刻。

2. eCAP 捕获功能核心配置 (Ultrasound_functionConfigure)

这段代码是整个测距系统的“灵魂”。我们需要捕获 Echo 的上升沿(高电平开始)和下降沿(高电平结束),并使用差分模式。

void Ultrasound_functionConfigure(void)
{
    // 1. 开启 eCAP 的时间戳计数器 (TSCTR)
    CAP_enableTimestampCounter(myCap);

    // 2. 设置捕获事件的停止值/环绕模式
    // 捕获模块最多支持4个事件,这里设置为在第2个事件 (CEVT2) 后环绕,即 0->1->2->0 循环
    CAP_setStopWrap(myCap,CAP_Stop_Wrap_CEVT2);

    // 3. 设置捕获事件的极性
    // 事件1 (CEVT1) 配置为上升沿捕获,记录 Echo 变高的时刻
    CAP_setCapEvtPolarity(myCap, CAP_Event_1,CAP_Polarity_Rising);
    // 事件2 (CEVT2) 配置为下降沿捕获,记录 Echo 变低的时刻
    CAP_setCapEvtPolarity(myCap, CAP_Event_2,CAP_Polarity_Falling);

    // 4. 设置计数器重置模式(关键:差分模式设计)
    // 开启事件1后的重置功能。这意味着在捕捉到上升沿时,不仅会记录当前时间,还会把计数器清零
    CAP_setCapEvtReset(myCap, CAP_Event_1, CAP_Reset_Enable);
    // 事件2不重置计数器。这样一来,事件2捕获到的时间值,直接就是上升沿到下降沿之间的时间差,无需软件再做减法!
    CAP_setCapEvtReset(myCap, CAP_Event_2, CAP_Reset_Disable);

    // 5. 设置为连续捕获模式,以便实时刷新测距数据
    CAP_setCapContinuous(myCap);

    // 6. 允许硬件在触发事件时,将计数器的值加载到 CAP1-4 寄存器中
    CAP_enableCaptureLoad(myCap);
}
3. 中断配置与距离计算 (isr.c 应用层逻辑)

首先我们需要开启 CEVT2 (捕获到下降沿) 的中断。当捕获完成时,CPU 会进入我们预设的中断服务函数。

定时器触发与结果获取:

// 定时器0中断:负责定时触发超声波模块
interrupt void myTimer_CpuTimer0_isr(void)
{
    ultrasound_on(Ultrasound); // 将 Trig 引脚拉高
    Delay(3000L);              // 延时保持高电平,确保满足至少 10us 的触发条件
    ultrasound_off(Ultrasound); // 将 Trig 引脚拉低,完成一次触发脉冲发送
    PIE_clearInt(myPie, PIE_GroupNumber_1); // 清除定时器中断标志位
}

// eCAP捕获中断:读取数据并计算距离
interrupt void myCap_CAPINT_isr(void)
{
    myCapVar1 = CAP_getCap1(myCap); // 获取事件1的捕获值(这里因为设置了 Reset,主要作为调试参考)
    myCapVar2 = CAP_getCap2(myCap); // 获取事件2的捕获值,由于差分模式,它直接代表了高电平的计数值

    // 核心公式计算:高电平计数值转换为距离
    distance = myCapVar2 * 170 / 600000;
    
    // 清除捕获中断和全局中断标志位,为下一次捕获做准备
    CAP_clearInt(myCap, CAP_Int_Type_CEVT2);
    CAP_clearInt(myCap, CAP_Int_Type_Global);
    PIE_clearInt(myPie, PIE_GroupNumber_4);
}

关于魔法公式 distance = myCapVar2 * 170 / 600000; 的解释:

根据前文提及的公式:距离 = 时间 * 340m/s / 2。也就是 距离 = 时间 * 170m/s。

这里的 myCapVar2 代表了单片机计时的 ticks 个数,结合 F28027 系统的时钟主频与 170m/s 的缩放因子,开发者在应用层化简得到了上述常量参数 170/600000 直接计算出距离值(cm)。


总结

以上就是基于 TI C2000 实现 HC-SR04 超声波测距的完整流程。我们利用了 F28027 强大的 eCAP 外设,通过配置 上升沿重置计数器 和 下降沿提取数据 的差分设计,把繁杂的时间差运算直接交给了硬件底层,极大地提升了软件运行效率和实时性。

大家在移植这套代码到自己的工程时,务必要注意 PIE 中断的使能以及系统时钟频率对最终测距公式参数的影响。有问题欢迎在评论区探讨交流!

更多推荐