在前面的实例中我们已经使用HRTOS完成了红外避障和雨滴传感器应用。本文继续介绍一个常见的8051传感器应用超声波测距。本例使用超声波模块测量目标距离并将测量结果以毫米mm为单位显示在4位数码管上。例如350mm → 0350 1250mm → 1250整个应用仍然采用HRTOS多任务结构将超声波数据采集和数码管显示分别交给不同任务处理。一、实现效果本例主要实现以下功能初始化超声波模块周期测量目标距离获取超声波驱动计算后的距离结果使用4位数码管显示距离采用独立任务完成测距和显示显示单位为mm例如测量距离为350mm数码管显示0350如果测量距离为1250mm则显示1250二、超声波测距的基本原理超声波测距通常通过发送超声波然后检测回波返回所需要的时间来计算距离。基本过程可以理解为发送超声波 ↓ 超声波传播 ↓ 遇到目标物 ↓ 产生回波 ↓ 接收回波 ↓ 计算传播时间 ↓ 换算距离因此超声波测距实际上是一个典型的时间测量应用。在8051中实现时需要对定时器、IO以及回波时间进行处理。不过在本例中这些底层工作已经由超声波驱动完成应用层只需要调用drv_ultrasonic_read();即可获得最终距离。三、驱动层已经完成数据处理本例的超声波驱动内部已经完成了多项数据处理工作包括多次采样 ↓ 数据排序 ↓ 去除最大值 ↓ 去除最小值 ↓ 平均值计算 ↓ 距离换算因此应用程序不需要再次处理原始回波时间。应用层最终获得的是距离值这样可以让应用程序更加简单。也就是说底层驱动 负责“怎么测” 应用程序 负责“测出来以后怎么用”这种驱动和应用分层的方式也比较适合实际嵌入式项目。四、超声波距离变量程序定义unsigned int ultrasonic_distance;用于保存当前测量距离。单位为mm例如ultrasonic_distance 350;表示当前测量距离为350mm使用unsigned int保存距离数据可以满足本例的测量范围要求。五、超声波测距任务超声波测量由独立任务负责void task_ultrasonic_read(void) { while(1) { ultrasonic_distance drv_ultrasonic_read(); os_delay(10); } }这个任务的工作流程非常简单开始任务 ↓ 读取距离 ↓ 保存测量结果 ↓ 延时 ↓ 再次测量 ↓ 循环其中drv_ultrasonic_read();负责获取超声波测量结果。而os_delay(10);让测距任务周期性运行。六、为什么测距任务需要周期执行超声波测距通常不需要在CPU上持续高速执行。测量一次以后可以等待一段时间再进行下一次测量。因此采用os_delay(10);让任务进入延时状态。任务延时期间HRTOS可以调度其他任务运行。整个过程可以理解为超声波任务 ↓ 开始测量 ↓ 获得距离 ↓ 任务延时 ↓ HRTOS运行其他任务 ↓ 再次调度 ↓ 开始下一次测量这种写法比较适合周期性传感器任务。七、数码管显示任务数码管显示由另一个任务负责void task_seg_display(void) { unsigned int distance; while(1) { distance ultrasonic_distance; drv_seg_display(0, distance / 1000); drv_seg_display(1, distance / 100 % 10); drv_seg_display(2, distance / 10 % 10); drv_seg_display(3, distance % 10); } }显示任务并不直接操作超声波模块。它只负责读取距离数据 ↓ 拆分数字 ↓ 显示到4位数码管因此两个任务的职责非常明确。八、距离数据如何拆分假设当前距离350mm那么程序将其拆分为千位0 百位3 十位5 个位0最终0350如果距离为1250mm则千位1 百位2 十位5 个位0显示1250程序通过以下代码完成drv_seg_display(0, distance / 1000); drv_seg_display(1, distance / 100 % 10); drv_seg_display(2, distance / 10 % 10); drv_seg_display(3, distance % 10);这种方法可以直接将0~9999范围内的整数拆分到4位数码管。九、HRTOS任务结构整个程序仍然采用两个任务HRTOS │ ┌────────┴────────┐ │ │ ▼ ▼ 超声波测距任务 数码管显示任务 │ │ ▼ │ drv_ultrasonic_read() │ │ │ ▼ │ ultrasonic_distance ──────────┘ │ ▼ 4位数码管超声波任务负责硬件 → 测量数据数码管任务负责测量数据 → 显示而HRTOS负责两个任务之间的调度。十、任务之间的数据共享本例采用全局变量unsigned int ultrasonic_distance;作为两个任务之间共享的数据。测距任务ultrasonic_distance drv_ultrasonic_read();负责更新数据。显示任务distance ultrasonic_distance;负责获取数据。因此数据流可以表示为超声波驱动 ↓ 测距任务 ↓ ultrasonic_distance ↓ 显示任务 ↓ 4位数码管对于这样简单的单个测量结果使用共享变量即可满足需求。如果后续需要实现多个任务之间更加复杂的数据传递则可以根据实际需求使用消息队列等HRTOS机制。十一、系统初始化在hrtos_main()中首先初始化超声波模块drv_ultrasonic_init();然后初始化数码管drv_seg_init();最后创建两个任务os_task_create( task_ultrasonic_read, 2, 2, 4 ); os_task_create( task_seg_display, 3, 2, 4 );整个启动过程可以表示为系统启动 ↓ 初始化超声波 ↓ 初始化数码管 ↓ 创建测距任务 ↓ 创建显示任务 ↓ HRTOS开始调度十二、完整程序#include hrtos.h #include hrtos_hal.h /* * * 超声波 4位数码管测距示例 * --------------------------------------------------------- * 功能 * 1. 初始化超声波模块 * 2. 测量超声波距离 * 3. 使用4位数码管显示距离 * * 显示单位 * mm * * 例如 * 350mm - 0350 * 1250mm - 1250 * * 超声波驱动内部已经完成 * 多次采样 * 数据排序 * 去除最大值和最小值 * 平均值计算 * 距离换算 * */ /*------------------------------------------------ * 超声波距离 * * 单位mm *------------------------------------------------*/ unsigned int ultrasonic_distance; /*------------------------------------------------ * 超声波测距任务 * * 周期读取距离 *------------------------------------------------*/ void task_ultrasonic_read(void) { while(1) { /* 读取超声波距离 */ ultrasonic_distance drv_ultrasonic_read(); /* * 稍作延时后再次测量 */ os_delay(10); } } /*------------------------------------------------ * 数码管显示任务 * * 显示4位距离数据 *------------------------------------------------*/ void task_seg_display(void) { unsigned int distance; while(1) { /* 获取当前距离 */ distance ultrasonic_distance; /* * 显示距离 * * 例如 * 0350mm - 0350 * 1250mm - 1250 */ drv_seg_display(0, distance / 1000); drv_seg_display(1, distance / 100 % 10); drv_seg_display(2, distance / 10 % 10); drv_seg_display(3, distance % 10); } } /** * brief 超声波测距示例初始化 */ void hrtos_main(void) { /* 初始化超声波模块 */ drv_ultrasonic_init(); /* 初始化数码管 */ drv_seg_init(); /* 创建超声波测距任务 */ os_task_create( task_ultrasonic_read, 2, 2, 4 ); /* 创建数码管显示任务 */ os_task_create( task_seg_display, 3, 2, 4 ); }十三、这个例子的特点这个例子和前面的雨滴传感器有一个明显的区别。雨滴传感器主要是模拟量 ↓ ADC ↓ 0~1023而超声波模块最终提供的是回波时间 ↓ 驱动处理 ↓ 距离 ↓ mm应用层并不需要了解超声波驱动内部的具体测量过程。只需要调用drv_ultrasonic_read();就可以直接得到距离。这说明一个完整的嵌入式驱动不仅可以完成硬件访问还可以将底层数据处理封装起来为上层应用提供更加直接的接口。十四、可以继续扩展什么在这个测距程序基础上还可以继续增加更多功能。例如设置距离报警测量距离 ↓ 判断是否小于阈值 ↓ ┌───┴───┐ ↓ ↓ 是 否 ↓ ↓ 蜂鸣器 正常 报警也可以增加LED距离较近 → LED亮 距离正常 → LED灭还可以增加按键用于修改报警距离。进一步可以增加串口通信超声波测距 ↓ 测距任务 ↓ 距离数据 ↓ 通信任务 ↓ 串口发送这样就可以将一个简单的超声波测距程序逐步扩展成更加完整的测距控制系统。十五、总结本文使用HRTOS完成了一个8051超声波测距应用。超声波驱动负责完成多次采样 数据处理 距离计算应用层则通过drv_ultrasonic_read();直接获取最终距离并通过4位数码管显示。程序采用两个独立任务task_ultrasonic_read ↓ 周期测量距离 task_seg_display ↓ 显示距离两个任务通过共享变量传递当前测量结果。通过这个例子可以看到在HRTOS应用中可以将硬件采集、数据处理和数据显示划分到不同的软件层次和任务中使应用程序保持清晰的结构。对于8051这样的资源受限平台这种模块化的组织方式同样可以用于温度、光照、距离、压力等各种传感器应用。
阅读完成 · 觉得有帮助?