基于TMS320F28027的智能小车开发(三):HC-SR04 超声波测距模块全解析:原理、eCAP捕获与代码逐行精讲
请点击: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 | 回响信号输出 |
它的核心逻辑可以概括为 “触发 - 发射 - 接收 - 计时” 四步:
触发:F28027 向 Trig 引脚输出一段持续时间 ≥ 10us 的高电平脉冲。
发射:模块响应触发信号,内部驱动电路自动生成 8 个连续的 40kHz 高频脉冲并通过探头(压电陶瓷振子)激发出超声波。
接收与计时:
在超声波脱离探头飞入空气的瞬间,模块立刻将 Echo 引脚拉为高电平;此时 F28027 的 eCAP 模块检测到上升沿,同步启动定时器开始计秒表。
超声波在空气中传播,遇到障碍物后反射形成回声。当模块的接收探头真正捕获到反射回来的超声波时,内部电路会瞬间将 Echo 引脚拉为低电平;F28027 检测到下降沿,立刻停止计时。计算: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 中断的使能以及系统时钟频率对最终测距公式参数的影响。有问题欢迎在评论区探讨交流!
更多推荐


所有评论(0)