在 Intel® Edison 板上使用带超声波测距传感器的 MCU
Intel® Edison 板除了 CPU 外,还包含一个内部微控制器单元 (MCU)。在本文中,我将解释使用内部 MCU 的优势,主要体现在两个方面:
获取新的 Intel® 物联网开发者套件,这是一个完整的硬件和软件解决方案,允许开发人员使用 Intel® Galileo 和 Intel® Edison 板创建令人兴奋的新解决方案。请访问 Intel® 物联网开发者专区。
Intel® Edison 板除了 CPU 外,还包含一个内部微控制器单元 (MCU)。在本文中,我将解释使用内部 MCU 的优势,主要体现在两个方面:
- 实时性
- 能效
MCU 在许多应用中都很重要。例如,Intel® Edison 板上的 Linux* 在处理传感器时无法提供实时响应。自 2.1 版以来,Intel® Edison® 板固件软件发行版一直支持 MCU。
让我们来看看 Intel® Edison 计算模块中使用的片上系统 (SoC)
Intel® Edison 计算模块中使用的 SoC 包含两个 CPU
- 双核 Intel® Atom™ 处理器,运行频率为 500 MHz。标记为主机 CPU。
- MCU,采用 Minute Intel® 架构,运行频率为 100 MHz。标记为MCU。
Minute Intel 架构核心是一种能效高的架构,基于 Intel® 486 并增加了与 Intel® Pentium® 处理器兼容的指令。MCU 包含丰富的 I/O 子系统(GPIO、I2C、高速 UART、DMA)和 SRAM,并且可以访问 Intel® Edison 计算模块的所有 GPIO 引脚。代码和数据的总 SRAM 大小为 192 kb。MCU 运行 WindRiver 的实时 Viper* OS。
MCU 程序在 Viper 核心上运行,并独立于 Intel Atom 处理器控制连接到 MCU 的外设。例如,它可以控制 GPIO 引脚,通过 I2C 和 UART 协议与传感器通信,以及与 Intel Atom 处理器通信。
使用 Intel® Edison 板上的 MCU 的原因
使用 MCU 有两个主要好处:提供微秒级的实时延迟和提高能效。
Intel Atom 处理器和 Yocto Project* 标准 Linux* 发行版“开箱即用”不支持实时应用程序。
Linux 应用程序可能会被调度器抢占,导致不可接受的、不可预测的延迟,因此无法提供实时响应。
MCU 运行单个应用程序和实时操作系统,这使得提供实时响应成为可能。
许多传感器都需要实时响应,因为通信协议依赖于对短时序的严格遵守。
要在没有内部 MCU 的情况下将这些传感器连接到 Intel® Edison 板,需要使用外部 MCU。在这种情况下,所有传感器通信都在外部 MCU 中实现。例如,SparkFun Block* for Intel® Edison board – Arduino extension board 提供了外部 MCU 功能。然而,使用外部 MCU 会增加物料清单 (BOM) 成本并增加解决方案的复杂性。
在 CPU 设置为睡眠状态,而 MCU 正等待外部事件(例如,当传感器值高于阈值时)的应用中,MCU 可以提高能效。
当外部事件发生时,MCU 会唤醒 CPU。实现示例可在文章 使用 MCU SDK 和 API:代码示例 中找到。
为了说明如何使用内部 MCU,我们将超声波测距传感器 HC-SR04 连接到 Intel® Edison 板。我们将把测量到的距离输出到 Grove* LCD RGB 背光显示屏。
超声波测距传感器 HC-SR04
该传感器有四个引脚
- Vcc:5V
- Trig:触发信号给传感器。MCU 向传感器发送一个 10 us 的脉冲。传感器启动一次测量。
- Echo:传感器到 MCU 的回波信号。脉冲宽度与测量距离成正比。
- Gnd:接地
下图在示波器屏幕上展示了该协议
- 通道 1:Trig
- 通道 2:Echo
MCU 向 Trig 引脚发送一个脉冲。之后,传感器通过 Echo 引脚发出响应脉冲。
脉冲持续时间与测量距离成正比。
距离计算使用以下公式(来自传感器数据手册)
距离 (cm) = Echo 脉冲持续时间 (us) / 58
根据数据手册,该传感器可以测量 2 cm 到 400 cm 的距离。
如果没有微秒级的实时延迟,则无法以估计的精度测量如此短的脉冲持续时间。例如,调度器可能会抢占测量过程,导致测量结果无效。
将 HC-SR04 传感器连接到 Intel® Edison 板上的 MCU
Components
- Intel® Edison 计算模块
- Intel® Edison 板(适用于 Arduino)
- Grove 基本扩展板
- Grove LCD RGB 背光
- 超声波测距传感器 HC-SR04
- 面包板
首先,组装 Intel® Edison 计算模块和 Intel® Edison 板(适用于 Arduino)。然后,将 Grove Base Shield 扩展板连接到 Intel® Edison 板(适用于 Arduino)。将 Grove LCD RGB 背光连接到 Grove Basic Shield 上的任意 I2C 端口。
按以下方式将超声波测距传感器 HC-SR04 连接到 Grove Basic Shield:
- Vcc 连接到 +5V
- Trig 连接到引脚 3
- Echo 连接到引脚 4
- Gnd 连接到 Gnd
引脚 3 和 4 是随机选择的。您可以为此目的使用任何 GPIO 引脚。
更新 Intel® Edison 板固件
MCU 支持已添加到 Intel® Edison 板固件软件发行版 2.1 版中。如果您使用的是旧版本固件,则需要更新。
要获取当前固件版本,请使用以下命令
# configure_edison –version
本示例基于固件版本 146。
固件更新说明可在文章 刷写 Intel® Edison 中找到。我更喜欢使用文章中描述的备选刷写方法。
请在刷写前仔细阅读说明。
通过以太网连接 Intel® Edison 板(通过 USB)
您必须配置网络连接才能从 MCU SDK 连接到 Intel® Edison 板。
为此,将 USB 线连接到顶部的 micro-USB 端口,并将拨动开关设置到底部位置(朝向 micro-USB 端口)。
在 Linux 上配置网络
# ifconfig usb0 192.168.2.2
Intel® Edison 板 IP 地址:192.168.2.15
有关更多信息,请参阅文章 通过以太网(USB 连接)连接到您的 Intel® Edison 板。
MCU SDK
开发人员需要 MCU SDK 来创建内部 MCU 的应用程序。MCU SDK 是一个基于 Eclipse* 的跨平台 IDE。安装过程在文章 安装 MCU SDK 中进行了说明。
MCU SDK 提供了创建、编译、上传到板以及调试 MCU 应用程序的功能。
与 MCU 通信
在 Linux 级别,有几种接口可用于与 MCU 通信
/dev/ttymcu0
— 用于发送/接收数据到/来自 MCU 的接口。可以使用标准的 Linux read
和 write
文件操作进行操作。MCU 程序可以使用 host_send
和 host_receive
函数。
/dev/ttymcu1
— 用于通过 debug_print 函数从 MCU 发送调试消息的接口。
/sys/devices/platform/intel_mcu/log_level
— 用于设置调试消息的日志级别的接口(fatal、error、warning、info、debug)。
使用 MCU 操作 Intel® Edison 板(适用于 Arduino)的引脚
MCU 集成在 Intel® Edison 计算模块中,可以控制 70 引脚 Hirose 模块连接器上的 GPIO。
要将 MCU 与 Intel® Edison 板(适用于 Arduino)一起使用,您需要找到 Intel® Edison 计算模块 GPIO 引脚与 Intel® Edison 板(适用于 Arduino)引脚之间的映射。配置多路复用器和电平转换器,将 GPIO 从 Intel® Edison 计算模块路由到 Intel® Edison 板(适用于 Arduino)的引脚。
在 Linux 级别工作时,这些例程由 MRAA 库处理。对于 MCU,开发人员需要使用脚本(init_DIG.sh、init_i2c8.sh、init_mcu_PWM.sh、set_DIG.sh、read_DIG.sh、init_UART1.sh)来处理。有关更多信息,请参阅 Intel® Edison Kit for Arduino* Hardware Guide 中的表 4。
Linux 脚本
下面的 Python* 脚本 show_distance.py 从内部 MCU 获取数据并在 Grove LCD 显示屏上显示。我们将使用 UPM 库中的 Jhd1313m1 模块来操作 Grove LCD 显示屏。
show_distance.py(注意:所有文件/脚本都作为 .zip 文件包含在本文章末尾)
import time import pyupm_i2clcd RET_ERROR = -1 if __name__ == '__main__': lcd = pyupm_i2clcd.Jhd1313m1(6, 0x3E, 0x62) with open('/dev/ttymcu0', 'w+t') as f: while True: f.write('get_distance\n') # Send command to MCU f.flush() line = f.readline() # Read response from MCU, -1 = ERROR value = int(line.strip('\n\r\t ')) lcd.clear() if value == RET_ERROR: lcd.setColor(255, 0, 0) # RED lcd.write('ERROR') else: lcd.setColor(0, 255, 0) # GREEN lcd.write('%d cm' % (value,)) time.sleep(1)
MCU 程序
MCU 程序等待来自主机 CPU 的 get_distance
命令。如果程序收到 get_distance
命令,它将测量距离并将结果发送到主机 CPU(距离以 cm 为单位,错误时为 -1)。
设置 Intel® Edison 板(适用于 Arduino)的引脚
# ./init_DIG.sh -o 3 -d output
# ./init_DIG.sh -o 4 -d input
MCU 操作 Intel® Edison 计算模块上的 GPIO 引脚,这些引脚的编号与 Intel® Edison 板(适用于 Arduino)上的标签不同。有关更多信息,请参阅文章 使用 MCU 闪烁 LED 中的表格。
mcu.c(注意:所有文件/脚本都作为 .zip 文件包含在本文章末尾)
#include "mcu_api.h"
#include "mcu_errno.h"
// Arduino Extension PIN = 3
#define TRIG 12
// Arduino Extension PIN = 4
#define ECHO 129
// From HC-SR04 datasheet
#define MIN_DISTANCE 2
#define MAX_DISTANCE 400
#define MAX_WAIT 10000
#define RET_ERROR -1
int get_distance() {
// Send Trig signal to HC-SR04
gpio_write(TRIG, 1);
mcu_delay(10);
gpio_write(TRIG, 0);
// Read Echo signal from HC-SR04
int i;
i = 0;
while ((gpio_read(ECHO) == 0) && (i < MAX_WAIT)) {
mcu_delay(1);
i++;
}
unsigned long t0 = time_us();
if (gpio_read(ECHO) == 0 || i == MAX_WAIT) {
return RET_ERROR;
}
i = 0;
while ((gpio_read(ECHO) == 1) && (i < MAX_WAIT)) {
mcu_delay(1);
i++;
}
unsigned long t1 = time_us();
if (gpio_read(ECHO) == 1 || i == MAX_WAIT) {
return RET_ERROR;
}
unsigned long distance = (t1 - t0) / 58;
if (MIN_DISTANCE < distance && distance < MAX_DISTANCE) {
return distance;
} else {
return RET_ERROR;
}
}
#define MAX_BUF 255
unsigned char buf[MAX_BUF];
void mcu_main() {
// Setup Trig as OUTPUT
gpio_setup(TRIG, 1);
// Initially set Trig to LOW
gpio_write(TRIG, 0);
// Setup Echo as INPUT
gpio_setup(ECHO, 0);
while (1) {
unsigned int len;
len = host_receive(buf, MAX_BUF);
if ((len >= 12) && (strncmp(buf, "get_distance", 12) == 0)) {
unsigned int distance;
distance = get_distance();
len = mcu_snprintf(buf, MAX_BUF, "%d\n", distance);
host_send(buf, len);
}
}
}
将我们的脚本添加到自动启动
要启动我们的脚本,首先创建一个 shell 脚本
文件/home/root/startup.sh
startup.sh(注意:所有文件/脚本都作为 .zip 文件包含在本文章末尾)
#!/bin/bash cd /home/root # configure PIN3 as GPIO OUPUT (TRIG signal) ./init_DIG.sh -o 3 -d output # configure PIN4 as GPIO INPUT (ECHO signal) ./init_DIG.sh -o 4 -d input python show_distance.py
将脚本标记为可执行文件
# chmod a+x /home/root/startup.sh
# chmod a+x /home/root/init_DIG.sh
Yocto Project Linux 使用 systemd,因此我们需要创建一个“service”文件来将脚本添加到自动启动。
创建文件/lib/systemd/system/startup-script.service
startup-script.service(注意:所有文件/脚本都作为 .zip 文件包含在本文章末尾)
[Unit] Description=Startup User Script After=syslog.target [Service] ExecStart=/home/root/startup.sh [Install] WantedBy=multi-user.target
将服务添加到自动启动
# systemctl enable startup-script
重启后,符号显示屏将显示测量到的距离