衡山派开发板驱动HC-SR04超声波测距模块:RT-Thread实战与代码移植详解

发布时间:2026/7/8 16:15:21

衡山派开发板驱动HC-SR04超声波测距模块:RT-Thread实战与代码移植详解 衡山派开发板驱动HC-SR04超声波测距模块RT-Thread实战与代码移植详解最近在做一个智能小车的项目需要用到超声波传感器来检测前方障碍物的距离。HC-SR04这个模块大家应该很熟悉了便宜又好用是很多嵌入式项目的入门选择。但很多朋友在把它移植到RT-Thread这样的实时操作系统上时总会遇到各种问题——引脚配置不对、定时器不准、测量结果跳动大。正好我手头有块衡山派HSPI开发板今天就带大家走一遍完整的移植流程。我会把代码逐行拆开讲清楚从硬件接线到Kconfig配置再到SCons构建和测试线程创建手把手教你如何在RT-Thread上稳定驱动HC-SR04。无论你是刚接触衡山派的新手还是想学习RT-Thread驱动开发的朋友这篇教程都能让你少走弯路。1. 准备工作了解HC-SR04与硬件连接1.1 HC-SR04模块工作原理HC-SR04超声波测距模块的工作原理其实很简单咱们先花两分钟搞明白它怎么工作的后面写代码时心里才有底。模块有四个引脚VCC电源、GND地、Trig触发和Echo回波。它的工作流程分三步触发咱们给Trig引脚一个至少10微秒的高电平信号。发射与接收模块收到触发信号后会自动发射8个40kHz的超声波脉冲然后开始等待回波。回波测量当模块接收到返回的超声波时Echo引脚会输出一个高电平。这个高电平的持续时间就是超声波从发射到返回所花费的时间。距离怎么算呢记住这个公式距离 (高电平时间 × 声速) / 2。声速在常温下大约是340m/s除以2是因为超声波走了个来回。实际计算时我们通常用距离(cm) 高电平时间(微秒) / 58这个58是怎么来的它是(34000 cm/s) / (2 × 1000000)约等于 0.017取倒数就是58.8图方便就用58了。模块的测量范围是2cm到600cm理论上精度标称0.3cm。如果被测物体超出范围Echo引脚会输出一个约66ms的固定高电平所以咱们的程序里要设置超时判断。1.2 硬件连接与引脚选择现在把模块接到衡山派开发板上。接线很简单HC-SR04引脚衡山派开发板引脚说明VCC3.3V 或 5V模块工作电压3-5.5V开发板上的3.3V或5V引脚都可以GNDGND共地一定要接TrigPE.14触发引脚需要配置为输出EchoPE.12回波引脚需要配置为输入注意原文驱动代码里固定使用了PE.14和PE.12这两个引脚。如果你需要改用其他引脚需要修改代码中的SR04_TRIG_PIN和SR04_ECHO_PIN宏定义。接好线后硬件部分就准备好了。接下来咱们进入软件部分看看怎么把现成的驱动代码集成到你的RT-Thread工程里。2. 代码移植把驱动放进你的工程2.1 获取驱动代码包首先你需要拿到HC-SR04的驱动代码。根据原始资料驱动代码包可以在相关资料下载中心找到具体路径在“模块移植资料下载”中。如果你已经下载了衡山派的SDK里面应该已经包含了这个驱动包。找到名为类似sr04-ultrasonic-ranging-sensor的文件夹这就是咱们需要的驱动代码。整个驱动包包含以下几个关键文件bsp_sr04.c/bsp_sr04.h核心驱动文件实现了初始化和测距函数。Kconfig菜单配置选项用于在menuconfig中启用这个驱动。SConscript构建脚本告诉SCons工具如何编译这些代码。test_sr04_ultrasonic_ranging_sensor.c测试用的线程示例方便我们验证驱动是否工作。你需要把这个驱动文件夹复制到你工程目录的特定位置。根据原文的说明路径是\luban-lite\application\rt-thread\helloworld\user-bsp\。如果你没找到user-bsp这个文件夹说明你还没进行模块移植的前置配置需要先参考相关手册完成必要的配置操作。2.2 修改Kconfig文件让驱动出现在配置菜单代码放进去之后RT-Thread还不知道它的存在。我们需要修改工程的Kconfig文件把驱动添加进去。用VSCode或其他编辑器打开你的工程找到这个文件application\rt-thread\helloworld\Kconfig。在这个文件的末尾#endif语句的前面添加下面这行代码# SR04超声波测距传感器 source application/rt-thread/helloworld/user-bsp/sr04-ultrasonic-ranging-sensor/Kconfig这行代码的作用是“引入”我们驱动包里的Kconfig配置。添加完成后保存文件。2.3 使用menuconfig启用驱动接下来我们要在RT-Thread的配置系统中启用这个驱动。首先进入你的工程根目录比如luban-lite文件夹双击运行win_env.bat脚本这会打开RT-Thread的env配置工具。在env命令行中输入以下命令列出所有可用的默认配置scons --list-def找到衡山派开发板对应的配置原文用的是d13x_JLC_rt-thread_helloworld。输入以下命令应用这个配置假设它在列表中是第7个scons --apply-def7或者直接用配置名scons --apply-defd13x_JLC_rt-thread_helloworld_defconfig应用配置后输入命令进入图形化配置菜单scons --menuconfig在菜单界面中用上下方向键找到并进入Porting code using the LCKFB module这个选项按回车进入。在这个子菜单里找到Use SR04 ultrasonic ranging sensor选项按Y键选中它前面会出现一个*号。提示在menuconfig里Y表示编译进固件M表示编译成模块N表示不编译。这里我们选Y。选中后按左右方向键选择Save保存配置然后一路退出菜单。2.4 编译与烧录配置保存好后就可以编译整个工程了。在env命令行中输入scons或者使用多核编译加快速度数字16表示使用的CPU核心数可以根据你的电脑配置调整scons -j16如果一切顺利编译完成后会在\luban-lite\output\d13x_JLC_rt-thread_helloworld\images\目录下生成一个d13x_JLC_v1.0.0.img的镜像文件。最后使用烧录工具如PhoenixSuit将这个镜像文件烧录到你的衡山派开发板中。烧录的具体教程可以参考衡山派官方文档中的“镜像烧录”部分。3. 驱动代码深度解析代码烧进去了但它到底是怎么工作的呢咱们来仔细看看核心的驱动文件bsp_sr04.c理解了原理以后调试和修改心里才有谱。3.1 引脚与定时器定义驱动一开始定义了几个关键的宏和变量#define SR04_TIMER_NAME hrtimer1 // 硬件定时器 #define SR04_TRIG_PIN PE.14 #define SR04_ECHO_PIN PE.12这里指定了Trig和Echo连接的引脚以及要使用的硬件定时器名称。定时器hrtimer1是衡山派芯片提供的一个高精度定时器用来精确测量Echo高电平的持续时间。3.2 核心测距函数 SR04_Read_Length这是整个驱动的核心我把它拆解开一步步讲。第一步发送触发脉冲rt_pin_write(SR04_TRIG, PIN_HIGH); // Trig拉高 aicos_udelay(15); // 保持高电平至少10us这里给15us留点余量 rt_pin_write(SR04_TRIG, PIN_LOW); // Trig拉低触发完成代码很简单就是给Trig引脚一个15微秒的高电平脉冲。aicos_udelay(15)是RT-Thread提供的微秒级延时函数。第二步等待Echo信号变高发送触发信号后模块开始发射超声波Echo引脚会从低电平变为高电平。我们需要等待这个上升沿while((Get_SR04_Echo() 0) timeout_us) // 等待Echo变高 { aicos_udelay(1); timeout_us--; }这里用了一个超时机制timeout_us初始值1000000即1秒防止因为模块故障或物体太远导致程序死等。第三步测量高电平持续时间一旦检测到Echo变高立刻启动定时器开始计时OpenTimer(); // 打开并启动硬件定时器 usHcCount_start aic_timer_get_us(); // 记录开始时刻的微秒数然后等待Echo信号从高变低回波结束while((Get_SR04_Echo() 1) timeout_us) // 等待Echo变低 { aicos_udelay(1); timeout_us--; }当Echo变低时停止定时器并记录结束时间CloseTimer(); // 关闭定时器 usHcCount_end aic_timer_get_us(); // 记录结束时刻的微秒数最后计算时间差并转换成距离uint32_t t GetEchoTimer(); // 获取经过的微秒数 length (float)t / 58.0f; // 换算成厘米公式距离(cm) 时间(us) / 58第四步滤波与平均超声波测量容易受到干扰单次读数可能不准。所以驱动里做了一个简单的软件滤波连续测5次用一个循环获取5个距离值存到数组里。冒泡排序对这5个值从小到大排序。去掉最高和最低去掉可能的最大误差值distances[0]和distances[4]。取中间3个的平均值用剩下的3个值求平均作为最终结果返回。// 对测量结果进行排序冒泡排序 for (int j 0; j 4; j) { for (int k 0; k 4 - j; k) { if (distances[k] distances[k 1]) { float temp distances[k]; distances[k] distances[k 1]; distances[k 1] temp; } } } // 剔除最高和最低值 sum - distances[0]; sum - distances[4]; // 计算三次平均值 return sum / 3.0f;这个方法虽然简单但在实际项目中能有效滤除偶然的干扰脉冲让读数更稳定。第五步测量周期控制根据HC-SR04的数据手册两次测量之间需要至少60ms的间隔对应最远测量距离。代码里用aicos_mdelay(65);等待了65毫秒保证了模块有足够的恢复时间。3.3 硬件定时器的作用你可能会问为什么不用简单的rt_thread_mdelay或者循环计数来计时呢因为Echo高电平的时间可能很短最近距离时只有几十微秒也可能很长最远距离时约60毫秒。软件延时精度不够而循环计数会被系统调度打断。所以这里用到了硬件定时器hrtimer1。驱动中SR04_HW_TIMER_Init函数初始化了这个定时器并将其配置为周期模式每1毫秒产生一次中断。在中断回调函数hrtimer_handle中只是简单地对一个毫秒计数器msHcCount进行加一操作。当需要计算总时间时GetEchoTimer函数会结合msHcCount毫秒部分和usHcCount_end - usHcCount_start微秒部分来计算出精确的微秒级时间差。这个设计巧妙地用1ms的定时器中断来扩展微秒计时器的量程避免了微秒计数器溢出比如aic_timer_get_us()返回的32位微秒值大约70分钟会溢出一次的问题。3.4 初始化与去初始化SR04_Init函数负责模块的初始化配置Trig引脚为输出Echo引脚为输入。将Echo引脚字符串如PE.12转换为底层HAL库需要的引脚编号。调用SR04_HW_TIMER_Init初始化硬件定时器。SR04_DeInit函数则用于释放资源主要是停止并关闭硬件定时器。在不需要测距或者程序退出时调用是个好习惯。4. 创建测试线程与验证驱动写好了怎么用起来呢原文提供了一个很好的示例test_sr04_ultrasonic_ranging_sensor.c。咱们来看看怎么创建一个线程来周期性地读取距离。4.1 测试线程详解这个测试文件定义了一个线程入口函数s r04_thread_entrystatic void sr04_thread_entry(void *param) { int while_count 1; SR04_Init(); // 初始化SR04模块 while(while_count) { float ret SR04_Read_Length(); // 读取距离 if(ret -RT_ERROR) { LOG_E(failed to SR04_Read_Length()); } else { // 打印距离格式化为“整数.小数”厘米 rt_kprintf(\nDistance: %d.%dcm\n, (int)ret,(((uint32_t)(ret*100))%100)); } // 每读取100次提示用户如何退出 if(while_count 100) { while_count 1; rt_kprintf(\nType [test_exit_sr04_sensor] command to exit [SR04]\n); rt_kprintf(Note: Pressing [TAB] as you type will autocomplete the command\n\n); rt_thread_mdelay(2000); } rt_thread_mdelay(500); // 每次读取间隔500ms } }线程的工作流程很清晰初始化后进入一个无限循环每隔500毫秒读取一次距离并打印出来。每读100次大约50秒会提示用户可以通过输入命令来退出测试。线程的参数定义在文件开头#define THREAD_PRIORITY 25 // 线程优先级 #define THREAD_STACK_SIZE 4096 // 线程栈大小 #define THREAD_TIMESLICE 10 // 时间片优先级25在RT-Thread中属于中等优先级栈大小4096字节对于这个简单的测距任务足够了。4.2 命令导出与使用为了让用户能在RT-Thread的MSH类似Shell命令行中控制这个测试代码导出了两个命令// 启动测试线程的命令 MSH_CMD_EXPORT(test_sr04, Test SR04 ultrasonic ranging sensor); // 退出测试线程的命令 MSH_CMD_EXPORT(test_exit_sr04_sensor, quit SR04 sensor);MSH_CMD_EXPORT是RT-Thread的一个宏它把C函数导出为Shell命令。第一个参数是函数名第二个参数是命令的简短描述。4.3 实际测试一切就绪后给开发板上电并通过USB转TTL模块连接串口波特率默认115200。在串口终端中你可以看到RT-Thread的启动信息和一个命令提示符。输入命令启动测试test_sr04提示输入test_后按TAB键可以自动补全命令。如果一切正常你会看到终端每隔0.5秒打印一次距离信息格式像这样Distance: 25.36cm Distance: 25.41cm Distance: 25.33cm你可以用手或书本在传感器前方移动观察距离值的变化。当你想停止测试时输入test_exit_sr04_sensor线程会被安全地删除并打印退出成功的消息。5. 常见问题与调试技巧移植过程中可能会遇到一些小问题这里分享几个我踩过的坑和解决办法测量结果一直是0或者超大值检查接线这是最常见的问题。确保VCC、GND、Trig、Echo四根线都接对了并且接触良好。检查引脚配置确认代码中的SR04_TRIG_PIN和SR04_ECHO_PIN宏定义与你实际的硬件连接一致。Trig必须是输出Echo必须是输入。检查电源HC-SR04虽然标称3.3V-5V但有些模块在3.3V下工作不稳定。可以尝试接到5V引脚并确保电源能提供足够的电流。测量值跳动很大软件滤波确保SR04_Read_Length函数里的5次测量取中值平均的滤波算法生效了。你可以适当增加测量次数比如7次或者调整滤波算法。环境干扰超声波对光滑的硬表面反射效果好但对海绵、布料等吸音材料效果差。确保被测物体表面适合超声波反射。延时时间两次测量之间aicos_mdelay(65);的等待时间不能少否则模块没准备好会影响下一次测量。编译时报错找不到头文件或函数检查Kconfig配置确保在menuconfig中确实选中了Use SR04 ultrasonic ranging sensor并且前面有*号。检查SConscript确认SConscript文件中的依赖条件GetDepend(LCKFB_SR04_SENSOR)和你配置中定义的宏名一致。清理后重新编译在env中执行scons -c清理工程然后再执行scons重新编译。定时器相关错误如果日志中出现Cant find hrtimer1 device!说明硬件定时器驱动没有正确启用。请检查RT-Thread的配置确保RT_USING_HWTIMER和AIC_USING_HRTIMER1这两个选项被启用。我们的Kconfig文件里已经通过select语句自动选择了它们但最好在menuconfig里确认一下。驱动移植是个细致活尤其是和时间相关的操作。多利用RT-Thread的rt_kprintf打印一些调试信息比如把计算出的原始时间差t打印出来看看是否在合理范围内最近距离约117us最远距离约35000us。掌握了基本原理和调试方法你就能轻松地把HC-SR04应用到你的衡山派项目中了无论是智能小车避障、液位检测还是自动门控制都能得心应手。

相关新闻