
在8051单片机项目中红外避障传感器是一种比较常见的基础传感器可以用于检测物体是否出现在传感器前方。本文使用HRTOS作为系统运行环境通过红外避障传感器读取当前检测状态并使用4位数码管实时显示检测结果。这个例子虽然功能比较简单但可以很好地体现HRTOS在实际8051项目中的基本任务划分方式红外传感器 ↓ 读取任务 ↓ 共享状态数据 ↓ 显示任务 ↓ 4位数码管最终通过两个独立任务完成传感器采集和数据显示。一、实现效果本例实现的功能非常简单初始化红外避障传感器周期性读取红外传感器状态使用4位数码管显示检测结果通过两个HRTOS任务分别完成数据采集和数据显示显示规则为0000 → 检测到障碍物 0001 → 未检测到障碍物例如检测到障碍物 0000未检测到障碍物0001这样即使没有串口也可以直接通过数码管观察传感器当前状态。二、程序整体结构本例的程序可以分成三个部分系统初始化 │ ├── 初始化红外传感器 │ ├── 初始化数码管 │ ├── 创建红外读取任务 │ └── 创建数码管显示任务系统运行以后task_ir_read │ │ 周期读取 ▼ ir_state │ │ ▼ task_seg_display │ ▼ 4位数码管其中ir_state是两个任务之间共享的数据。三、红外避障状态程序定义了一个变量unsigned char ir_state 1;用于保存当前红外避障传感器的状态。红外读取任务通过驱动接口ir_state drv_ir_read();获得当前状态。本例约定0 → 检测到障碍物 1 → 未检测到障碍物因此ir_state就成为传感器任务和显示任务之间的数据接口。四、红外传感器读取任务红外传感器由独立任务负责读取void task_ir_read(void) { while(1) { ir_state drv_ir_read(); os_delay_ms(50); } }这个任务的工作流程非常清晰读取传感器 ↓ 保存状态 ↓ 延时50ms ↓ 再次读取 ↓ 循环其中drv_ir_read();负责访问红外传感器。而os_delay_ms(50);负责让当前任务延时50ms。五、为什么要周期读取红外避障传感器的状态可能随着物体移动而发生变化因此程序需要周期性读取。本例设置为os_delay_ms(50);也就是每隔一段时间读取一次传感器。这种方式比在程序中不断高速轮询更加合理。任务完成一次读取以后就进入延时状态。在这段时间内HRTOS可以调度其他任务运行。因此整个系统可以形成读取红外 ↓ 任务延时 ↓ CPU运行其他任务 ↓ 再次调度红外任务 ↓ 读取红外这就是RTOS中比较典型的周期任务。六、数码管显示任务数码管由另外一个任务负责void task_seg_display(void) { while(1) { drv_seg_display(0, 0); drv_seg_display(1, 0); drv_seg_display(2, 0); drv_seg_display(3, ir_state); } }这个任务不直接读取红外传感器。它只负责读取ir_state然后把状态显示到4位数码管上。因此两个任务的职责非常明确红外读取任务 │ ▼ ir_state │ ▼ 数码管显示任务七、为什么要把读取和显示分成两个任务这是这个例子比较重要的地方。如果使用传统的单循环程序可以写成while(1) { ir_state drv_ir_read(); drv_seg_display(0, 0); drv_seg_display(1, 0); drv_seg_display(2, 0); drv_seg_display(3, ir_state); }功能当然也可以实现。但是随着项目不断增加功能主循环可能变成读取红外 读取温度 读取按键 刷新数码管 处理串口 处理蜂鸣器 处理通信 处理其他传感器 ……代码会逐渐集中到一个循环里面。使用HRTOS以后可以按照功能拆分红外任务 ↓ 负责红外传感器 显示任务 ↓ 负责数码管 温度任务 ↓ 负责温度传感器 通信任务 ↓ 负责串口通信每个任务承担相对独立的职责。这也是RTOS比较重要的价值之一不仅仅是提供任务调度更重要的是帮助组织复杂的嵌入式应用程序。八、两个任务之间的数据传递本例暂时没有使用消息队列或信号量而是直接通过全局变量共享数据unsigned char ir_state 1;红外读取任务负责修改ir_state drv_ir_read();数码管任务负责读取drv_seg_display(3, ir_state);因此可以简单理解为ir_state │ ┌──────┴──────┐ │ │ ▼ ▼ 写入数据 读取数据 │ │ ▼ ▼ 红外读取任务 显示任务对于这种非常简单的状态数据直接共享一个变量就可以完成基本功能。当应用程序进一步复杂以后就可以根据实际需求使用HRTOS提供的消息队列、信号量等机制。九、4位数码管显示本例使用4位数码管显示0000或者0001前三位固定显示drv_seg_display(0, 0); drv_seg_display(1, 0); drv_seg_display(2, 0);最后一位显示传感器状态drv_seg_display(3, ir_state);因此ir_state 0 0000表示检测到障碍物而ir_state 1 0001表示未检测到障碍物这种显示方式虽然简单但非常适合做传感器驱动验证。只要移动物体靠近或者远离红外传感器就可以直接观察数码管的变化。十、系统初始化所有任务启动之前需要先初始化硬件void hrtos_main(void) { drv_ir_init(); drv_seg_init(); os_task_create( task_ir_read, 2, 2, 4 ); os_task_create( task_seg_display, 3, 2, 4 ); }首先初始化红外避障传感器drv_ir_init();然后初始化4位数码管drv_seg_init();最后创建两个任务。十一、任务创建红外读取任务os_task_create( task_ir_read, 2, 2, 4 );数码管显示任务os_task_create( task_seg_display, 3, 2, 4 );两个任务分别负责不同功能。从应用程序角度来看可以简单理解为任务2 └── 红外传感器读取 任务3 └── 数码管显示具体的任务调度和运行由HRTOS负责。应用程序只需要关注自己的功能逻辑。十二、完整程序下面是本例的完整HRTOS应用代码#include hrtos.h #include hrtos_hal.h /* * * 红外避障 4位数码管显示示例 * --------------------------------------------------------- * 功能 * 1. 初始化红外避障传感器 * 2. 读取红外避障状态 * 3. 使用4位数码管显示检测状态 * * 显示 * 0000检测到障碍物 * 0001未检测到障碍物 * */ /*------------------------------------------------ * 红外避障状态 *------------------------------------------------*/ unsigned char ir_state 1; /*------------------------------------------------ * 红外避障读取任务 *------------------------------------------------*/ void task_ir_read(void) { while(1) { /* 读取红外避障状态 */ ir_state drv_ir_read(); /* * 周期读取传感器状态 */ os_delay_ms(50); } } /*------------------------------------------------ * 数码管显示任务 *------------------------------------------------*/ void task_seg_display(void) { while(1) { /* * 显示红外避障状态 * * 0检测到障碍物 * 1未检测到障碍物 */ drv_seg_display(0, 0); drv_seg_display(1, 0); drv_seg_display(2, 0); drv_seg_display(3, ir_state); } } /** * brief 红外避障示例初始化 */ void hrtos_main(void) { /* 初始化红外避障传感器 */ drv_ir_init(); /* 初始化数码管 */ drv_seg_init(); /* 创建红外避障读取任务 */ os_task_create( task_ir_read, 2, 2, 4 ); /* 创建数码管显示任务 */ os_task_create( task_seg_display, 3, 2, 4 ); }十三、这个例子的意义这个例子的代码量并不大但是已经包含了一个典型的嵌入式RTOS应用结构HRTOS │ ┌───────┴───────┐ │ │ ▼ ▼ 红外读取任务 数码管显示任务 │ │ ▼ │ drv_ir_read() │ │ │ ▼ │ ir_state ───────────┘ │ ▼ drv_seg_display()可以看到驱动层负责操作具体硬件任务层负责组织具体功能HRTOS负责任务调度和延时应用数据负责连接不同功能模块。这种结构也是后续构建更复杂8051应用的基础。十四、后续可以如何扩展在这个基础上还可以继续增加很多功能。例如增加蜂鸣器检测到障碍物 ↓ 数码管显示0000 ↓ 蜂鸣器报警也可以增加LED检测到障碍物 → LED亮 未检测到障碍物 → LED灭还可以增加按键按键 ↓ 修改工作模式 ↓ 红外任务按照新的模式工作如果进一步增加温度传感器、RTC、串口通信等就可以逐渐形成一个更加完整的多任务8051应用。十五、总结本文使用HRTOS完成了一个简单的8051红外避障应用。程序主要由两个任务组成task_ir_read ↓ 周期读取红外传感器 task_seg_display ↓ 显示当前检测状态两个任务通过unsigned char ir_state;共享传感器状态。整个程序结构非常简单但已经体现了HRTOS应用开发的基本思想一个任务负责一个相对独立的功能。当项目规模逐渐扩大以后可以继续使用任务、信号量、互斥锁、消息队列等机制将不同功能模块组织起来。对于8051这样资源有限的单片机来说RTOS并不只是为了让程序“看起来像一个操作系统”更重要的是在有限资源下建立更加清晰、可维护的应用程序结构。后续还可以继续使用HRTOS完成传感器、显示、通信、控制等更多8051实际应用案例。