在前面的实例中我们使用HRTOS完成了DS1302实时时钟和红外避障传感器的应用。本例继续使用HRTOS进行8051传感器应用开发这次使用雨滴传感器的AO模拟输出通过单片机ADC读取雨滴传感器的模拟量并将ADC转换结果实时显示在4位数码管上。与红外避障传感器直接输出0和1不同雨滴传感器的AO接口输出的是连续变化的模拟量因此这个例子可以进一步展示HRTOS在模拟量采集、多任务处理和数据显示方面的基本应用。一、实现效果本例实现以下功能初始化雨滴传感器使用AO接口读取模拟量通过ADC将模拟信号转换为数字量使用4位数码管显示ADC转换结果使用独立任务周期性采集雨滴传感器数据本例ADC采用10位分辨率0 ~ 1023因此数码管显示范围为0000 ~ 1023例如0256表示当前ADC转换结果为256。二、雨滴传感器AO和DO常见雨滴传感器模块通常提供两个输出接口AO → 模拟输出 DO → 数字输出两者的用途有所不同。AO模拟输出AO输出的是随传感器状态变化而变化的模拟信号。通过ADC可以将模拟信号转换成数字量雨滴传感器 ↓ AO ↓ ADC ↓ 0 ~ 1023因此AO适合用于观察雨滴传感器的连续变化。DO数字输出DO通常经过模块上的比较电路处理可以根据模块设定的阈值输出数字状态。因此DO更加适合用于是否超过某个阈值而AO则可以获得更加详细的模拟数据。本例主要使用AO进行ADC采集。三、ADC转换结果本例采用10位ADC。10位ADC能够表示2^10 1024个不同的数字量因此转换结果范围为0 ~ 1023程序中使用unsigned int raindrop_value 0;保存ADC转换结果。之所以使用unsigned int是因为8051中的unsigned char最大只能保存255而ADC最大值可以达到1023。因此unsigned char 0 ~ 255无法完整保存10位ADC结果。而unsigned int可以满足本例的数据范围要求。四、雨滴传感器读取任务本例将雨滴传感器的采集独立设计成一个任务void task_raindrop_read(void) { while(1) { raindrop_value drv_raindrop_read_ao(0); os_delay(10); } }任务的主要工作流程为读取AO ↓ ADC转换 ↓ 保存结果 ↓ 任务延时 ↓ 再次读取其中drv_raindrop_read_ao(0);负责读取雨滴传感器AO模拟量。参数0表示本例使用的ADC通道。五、为什么采集任务需要延时传感器数据并不需要以最高速度不停读取。例如raindrop_value drv_raindrop_read_ao(0);完成一次ADC采集以后可以让任务暂时进入延时状态。本例使用os_delay(10);这样可以避免采集任务持续占用CPU。任务进入延时以后采集任务 ↓ 进入延时 ↓ HRTOS运行其他任务 ↓ 延时结束 ↓ 再次采集这也是HRTOS中周期性传感器任务的典型写法。注代码中的os_delay(1 0)如果是实际源码应改为合法的os_delay(10)本文按10个时间单位的周期采集来说明。六、数码管显示任务采集任务负责获取数据而数码管显示任务负责显示数据void task_seg_display(void) { unsigned int value; while(1) { value raindrop_value; drv_seg_display(0, value / 1000); drv_seg_display(1, value / 100 % 10); drv_seg_display(2, value / 10 % 10); drv_seg_display(3, value % 10); } }可以看到显示任务没有直接访问雨滴传感器。它只需要读取raindrop_value然后进行数字拆分。这样就把数据采集和数据显示分成了两个独立功能。七、ADC数值如何拆分到4位数码管假设ADC转换结果为1023那么4位数码管需要显示1 0 2 3程序通过以下方式进行拆分value / 1000得到千位1然后value / 100 % 10得到百位0再通过value / 10 % 10得到十位2最后value % 10得到个位3因此ADC 1023 第0位 → 1 第1位 → 0 第2位 → 2 第3位 → 3最终显示1023八、例如ADC值为256假设当前雨滴传感器ADC转换结果为256程序计算256 / 1000 0 256 / 100 % 10 2 256 / 10 % 10 5 256 % 10 6所以数码管显示0256这种显示方式可以直接观察ADC数据变化。例如传感器状态发生变化以后ADC值可能随之变化0100 0256 0438 0682 ...通过数码管即可直观看到ADC数据的变化过程。九、HRTOS中的任务划分本例仍然采用两个任务HRTOS │ ┌───────┴───────┐ │ │ ▼ ▼ 雨滴传感器读取任务 数码管显示任务 │ │ ▼ │ ADC采集 │ │ │ ▼ │ raindrop_value ────────┘ │ ▼ 4位数码管第一个任务负责硬件 → 数据第二个任务负责数据 → 显示这种结构与前面的红外避障例子非常类似。区别在于红外避障主要得到的是0 / 1而雨滴传感器AO得到的是0 ~ 1023因此本例进一步展示了模拟量数据在HRTOS任务中的处理方式。十、系统初始化系统启动以后首先初始化雨滴传感器drv_raindrop_init();然后初始化数码管drv_seg_init();最后创建两个任务os_task_create( task_raindrop_read, 2, 2, 4 ); os_task_create( task_seg_display, 3, 2, 4 );整个初始化过程可以表示为系统启动 ↓ 初始化雨滴传感器 ↓ 初始化数码管 ↓ 创建ADC采集任务 ↓ 创建显示任务 ↓ HRTOS开始调度十一、完整程序完整代码如下#include hrtos.h #include hrtos_hal.h /* * * 雨滴传感器 4位数码管显示示例 * --------------------------------------------------------- * 功能 * 1. 初始化雨滴传感器 * 2. 读取AO模拟量 * 3. 使用4位数码管显示ADC转换结果 * * ADC分辨率 * 10位 * * ADC范围 * 0 ~ 1023 * * AO * 模拟输出数值随雨滴传感器状态变化 * * DO * 数字输出可用于判断是否达到模块设定阈值 * */ /*------------------------------------------------ * 雨滴传感器ADC值 *------------------------------------------------*/ unsigned int raindrop_value 0; /*------------------------------------------------ * 雨滴传感器读取任务 *------------------------------------------------*/ void task_raindrop_read(void) { while(1) { /* * 读取AO模拟量 * * 这里使用P1.0作为ADC输入。 */ raindrop_value drv_raindrop_read_ao(0); /* * 周期读取 */ os_delay(10); } } /*------------------------------------------------ * 数码管显示任务 *------------------------------------------------*/ void task_seg_display(void) { unsigned int value; while(1) { /* 获取当前ADC值 */ value raindrop_value; /* * 显示10位ADC结果 * * 范围 * 0000 ~ 1023 */ drv_seg_display(0, value / 1000); drv_seg_display(1, value / 100 % 10); drv_seg_display(2, value / 10 % 10); drv_seg_display(3, value % 10); } } /** * brief 雨滴传感器示例初始化 */ void hrtos_main(void) { /* 初始化雨滴传感器 */ drv_raindrop_init(); /* 初始化数码管 */ drv_seg_init(); /* 创建雨滴传感器读取任务 */ os_task_create( task_raindrop_read, 2, 2, 4 ); /* 创建数码管显示任务 */ os_task_create( task_seg_display, 3, 2, 4 ); }十二、这个例子和前面的红外避障有什么区别前面的红外避障传感器主要用于判断有没有障碍物因此得到的数据比较简单0 / 1而本例使用雨滴传感器的AO输出可以得到0 ~ 1023因此它可以提供更加连续的传感器数据。从HRTOS应用设计角度来看两者仍然采用相同的结构传感器读取任务 ↓ 共享数据 ↓ 显示任务这说明这种任务划分方式并不依赖于某一种具体传感器。以后换成光敏传感器 电位器 模拟温度传感器 气体传感器 压力传感器同样可以采用类似的结构。十三、进一步扩展在这个例子的基础上可以继续增加更多功能。例如增加阈值判断ADC值 ↓ 超过阈值 ├── 是 → 报警 └── 否 → 正常可以增加蜂鸣器检测到雨水 ↓ 蜂鸣器报警也可以增加LED正常状态 → LED灭 雨滴较多 → LED亮还可以将ADC数据通过串口发送给上位机雨滴传感器 ↓ ADC采集 ↓ HRTOS任务 ↓ 消息队列 ↓ 串口通信任务 ↓ PC这样就可以从一个简单的传感器显示程序逐渐扩展成完整的嵌入式应用。十四、总结本文使用HRTOS实现了一个8051雨滴传感器应用。程序通过雨滴传感器的AO接口获取模拟量并利用10位ADC将其转换为0 ~ 1023随后通过4位数码管实时显示ADC转换结果。程序主要由两个任务组成task_raindrop_read ↓ 周期采集ADC数据 task_seg_display ↓ 显示ADC转换结果两个任务通过unsigned int raindrop_value;进行数据共享。通过这个例子可以进一步看到HRTOS在8051传感器应用中的一种基本使用模式采集任务负责获取数据显示任务负责处理和展示数据HRTOS负责多个任务之间的调度。从数字量传感器到模拟量传感器虽然数据形式发生了变化但应用程序的任务组织方式仍然可以保持清晰、独立的结构。这也是在资源有限的8051平台上使用RTOS构建实际应用的一种常见方式。