(极客直接跳到挑战和现有解决方案部分)
用于监控各种环境和天气条件(温度、湿度、压力、光线、雨水、气体、运动)的(自制)物联网系统的设计和部署已成为每个(初级)爱好者所做的最受欢迎的项目之一一生至少一次。来自 OEM 和 DIY 套件供应商的硬件构建块的可用性,以及大量的免费软件(开源、现成的解决方案、库、驱动程序、IDE、应用程序、操作系统、云中间件等)已经使项目纯粹是明智的。设计师的角色通常被简化为只选择正确的传感器模块,这些模块连接到“强大”的 MCU 板(ESP32 、Raspberry 、Arduino),将现有软件(驱动程序、库)粘合在一起,并编写简单的应用程序逻辑。更不用说无数的指南、博客和 YouTube 教程了。
这种方法具有许多优点,例如快速原型制作、不需要深入的知识和经验、非常有趣、大量支持以及没有(或显着减少)挫折感。对于那些决定进一步推进该项目并希望在其财产中/周围构建和部署大量传感器,甚至商业化(至少将解决方案出售给您的朋友或家人)的少数人来说,这种方法有几个缺点。最重要的是解决方案的整体价格(如果你卖掉它,利润会更低)。事实上,它可能比知名品牌的高价产品便宜。但是,使用ESP32 (双核 32 位 @ 160 或 240MHz、320 KiB RAM、448 KiB ROM CPU 以及大量 IO 和总线)从臭名昭著的传感器(例如DHT11, DHT22 , DS18B20 , AM2320 , BMP280 ) 通过 SPI/I2C/单线总线。除此之外,使用 Wi-Fi 将几个字节转发到中央集线器(另一个 ESP32 或 Raspberry)与(能源)效率无关。蓝牙低功耗 (BTE) 配置文件可能会有所改进,但是,模块(例如HC-05)的价格比 MCU 本身(包括一些传感器)贵数倍。
综上所述,小型物联网传感器主要有两个非功能性需求:
对于通信模块,有多种 COTS 选项可以同时满足低成本和超低功耗的需求。其中之一是收发器nRF24L01+,特别受创客和爱好者的欢迎。它价格低廉(中国网上商店的分线板从 0.8 美元起)和超低功耗(掉电模式下为 990nA,待机模式下为 22uA,最大功率下 TX/RX 期间为 12mA)。此外,它具有简单的接口(尽管是 3.3V 供电设备,但具有 5V 容限逻辑引脚的 SPI)、许多有利的特性(例如 ISM 频带 2.4GHz,范围从 100 到 1000m、0.5-1-2 Mbps 带宽、自动-retransmit、auto CRC check、multiciever)、大量廉价(突破)模块(见下文)和几个 SW 库(nRF24 用于 Arduino/Raspberry Linux )。
受爱好者欢迎的典型低端(成本)MCU 是8 位 AVR子系列,带有称为ATtiny的有限外设集,特别是 8 针25/45/85和 14 针24/44/84版本(第一个数字是以 KiB 为单位的闪存大小)。Arduino 的 28 针ATmega328P属于 ATmega 系列,具有广泛的外设和指令集。它提供 32KiB 闪存、4 倍更大的 RAM、更多 IO 设备,而且价格更高。在 (PCB) 尺寸、低引脚数和成本非常重要的情况下,ATtiny 系列 25/45/85 和 24/44/84 可能比 328P 更可取。
另一个有趣的低端 MCU 是带有 1KiB 闪存和 64B SRAM的 8 针ATtiny13A 。它比 25/45/85 和 24/44/84 ATtiny 系列便宜 2-4 倍(< 1 美元)并且消耗更少的能量。因此,它在小型、简单、电池供电的低成本设计(大多数无线传感器都是如此)中特别受欢迎。
将 ATtiny13A 与低功耗无线模块 nRF24L01+ 相结合,对于满足上述非功能性要求的物联网传感器来说,似乎是一个可行的选择。
为什么有人会费心将 nRF24L01+ 安装在 8 针微型 ATtiny13A 和 1 KiB 闪存上的另一个原因,该闪存已经有 3 个针脚被超低功耗设备中的传感器占用,这是……只是为了玩得开心,大笑,很棒有趣,因为:
“在 2K 中,你几乎没有刷牙的空间。”
-乔·德库尔
由于硬件和软件的挑战,低端 8 针 ATtiny13A 与 nRF24L01 的组合并非易事。在我们对通用 8 引脚 MCU 的评论中,我们更详细地描述了这种结合所面临的硬件和软件挑战。回想一下,硬件挑战如下图所示:
ATtiny13A 实际上有 5 个引脚。如果我们将 PB5 从其主要功能(RESET/dWIRE)重新编程到 IO 端口,我们有 6 个引脚。但是,所有 6 引脚的使用都需要高压编程。这对于在线串行编程 (ICSP) 并不总是可行的。此外,我们没有任何备用引脚用于连接传感器或连接到现场总线。从审查的现有解决方案来看,所有硬件提案原则上都适用于 ATtiny13A ,但每个都有相关的“成本”:
不幸的是,并非所有经过审查的软件解决方案都具有足够低的内存占用和/或支持所有功能:
总而言之:所有列出的硬件解决方案都只优化了一个参数——引脚数。它们都没有同时优化 1)能耗、2) 引脚数和3) 代码占用空间。这对于超低功耗应用至关重要。此外,还缺少一个合适的 SW 驱动程序来支持半双工无线通信,该驱动程序可以适合 t13a 以及支持一些引脚数优化解决方案。我们认为还有进一步提升的空间。出于这个原因,我们设计了一个全新的 SW 库,将在本文的其余部分进行描述。该库支持以下分别描述的三种硬件配置:
CE 和 CSN 都是输入引脚,根据nRF24 产品规范:
由此我们可以识别出共享 CE/CSN 信号的以下情况:
1) CE/CSN 为低电平,SCK 上无脉冲:默认情况,未启用无线电,nRF24 不受影响。
2) CE/CSN 为低电平,SCK 上的时钟信号:MCU 和 nRF 模块之间通过 SPI 传输数据。
3) CE/CSN 上的脉冲大于 50ns 且小于 10us :复位 SPI 接口并指示新事务的开始。
4) CE/CSN 上的10us脉冲:如果模块之前处于StandBy-1模式(通过 SPI 接口设置配置寄存器中的 PWR_UP 位激活),则启用无线电模式(TX 或 RX)。
5) 将 CE/CSN 拉高 10us 以上:在 RX 模式下用于等待新消息。
我们将使用条件 (1) CE/CSN 低作为信号的默认状态。我们是否要启用/禁用无线电(通常由 CE 控制)或通过 SPI 读/写寄存器(通常由 CSN 控制)的选择将使用不同的脉冲持续时间“编码”。
如果我们想在 SPI 上执行事务(访问控制/状态寄存器和 TX/RX 数据缓冲区),该过程将采取以下步骤:
要启用收音机,让我们首先看看 TX 模式。在我们切换到 TX 模式之前,我们必须正确配置 nRF24 模块(上电,进入StandBy-1模式)并将数据上传到 TX 缓冲区。这是通过上述常规 SPI 事务和步骤完成的。之后,触发传输的过程将采取以下步骤:
模块将切换到 TX 模式,将执行所有操作(传输、等待确认、重传、超时),并且在所有 TX 缓冲区为空后将切换回StandBy-1模式,因为 CE 为低电平。如果我们一直保持 CE 为高电平,即使缓冲区为空,模块也会进入StandBy-2状态。不同之处在于功耗:22uA 与 320uA,即StandBy-2 的15 倍。这样的功耗等于完全激活状态下 1MHz 的 ATtiny13A。模块将停留在StandBy-1直到 MCU 将 nRF24 池化为状态并最终关闭无线电(PWR_UP=0 位),即切换到PowerDown仅消耗 990nA 的状态。CE 上的这个短脉冲节省了一些能量,这在超低功耗应用中确实很重要。
接收(RX模式)的情况略有不同,因为我们要等待比较长的一段时间才能接收到一些数据。在 CE/CSN 上执行 10us 的短脉冲是不够的。一种选择是将 CE/CSN 保持高电平一段所需的时间。在此期间,我们无法使用 SPI 访问 nRF24。这个问题可以通过在发送端设置足够多的重传、超时和消息确认属性来缓解。应配置 SPI 事务读取状态寄存器的持续时间短于整个传输会话(包括重新传输)。该程序将采取以下步骤:
此解决方案适用于主要用于传输的设备,但对于预期设备永久处于接收器模式的情况效果较差。对于这种情况,不合并 CE 和 CSN 可能更有效。相反,将 CE 拉至 Vcc(高电平)将使 ATtiny13A 无需关闭无线电即可汇集新消息。
这个想法是通过一个电阻将 SPI 数据信号 MOSI 和 MISO 合并为一个,如下图所示:
这不是一个新想法,在各种设计中相对常见,以减少信号的数量。nRF24 模块会在这样的信号合并下正常工作吗?此图中显示了 SPI 与文档中的 nRF24 模块的通信:
我们看到nRF24使用MISO发送状态字节,而主控(MCU)向模块发送命令,即全双工通信。之后,MISO 线下降,仅在主 (MCU) 请求读取操作时使用。两个信号之间唯一可能的干扰是在开始时可能会破坏命令字节(在 MOSI 线上)。幸运的是,这种“冲突”是通过电阻解决的。其值应保证信号源/漏极不跨越 MCU 和模块的引脚特性。在我们的案例中,从 4.7k 到 10k 的值运行良好。
合并的 MISO/MOSI 节省了一个可用于直接控制 CE 的引脚。如果需要,可以将此配置与第一个配置混合使用 - 共享 CE/CSN,如下图所示:
这种配置降低了 MISO(主输入,从输出)线,使其成为 3 线 SPI,即减少了一个引脚数。我们可以将数据写入 nRF24 模块,但我们将无法读取它们:
它可能非常严格,但适用于某种类型的无线应用程序 - 设备专门用作数据源(测量),它不接收来自其他设备或网关(中央集线器)的数据。如果我们可以有一个 3 线 SPI 来节省相同数量的引脚,为什么我们还需要单向 SPI?有两个原因:
我们可以将此配置与第一个配置(共享 CE/CSN)相结合,以进一步优化 MCU 所需的引脚数,如下图所示:
代码在 C ( nRF24L01.c
) 和汇编程序 ( nRF24L01_asm.S
) 中都实现。头文件nRF24L01.h
包含重要的常量和 API 函数的声明。默认情况下,该库使用全 4 线 SPI 和独立的 CE 和 CSN 信号。通过在文件中定义相应的宏来配置库以使用上述硬件选项之一。projdefs.h
#define NRF24L01_SHARED_CE_CSN // For shared CE/CSN configuration
此宏可以与以下任一(或无)组合:
#define NRF24L01_3WIRE_SPI // If used 3-wire SPI (with resistor)
#define NRF24L01_DO_NOT_USE_MISO // Uni-directional configuration
如果上述三个宏均未定义,则假定为默认配置。
定义连接到哪些端口 nRF24 信号也通过projdefs.h
标头中的宏完成。引脚配置宏是:
// MANDATORY macros for port output, port direction and pin reading:
#define NRF24L01_PORT PORTB
#define NRF24L01_DDR DDRB
#define NRF24L01_INPORT PINB
为特定的引脚配置定义以下宏(如果适用 - 请参阅上面的功能):
#define NRF24L01_CE PB0 // Optional. Do not define if shared CE/SCN is enabled
#define NRF24L01_CSN PB2 // Mandatory
#define NRF24L01_SCK PB1 // Mandatory
#define NRF24L01_MOSI PB3 // Mandatory
#define NRF24L01_MISO PB4 // Optional. Define only if 4-wire SPI is used.
API 只有 8 个(或 6 个,如果是单向的)方法。必须调用的第一个函数是初始化:
void nrf24_init(void);
其余功能根据 SPI 事务的长度进行拆分。零字节命令通过以下方式调用:
void nrf24_cmd(uint8_t cmd);
参数是文档表 16 中的“命令字” ,例如:FLUSH_TX
, FLUSH_RX
, REUSE_TX_PL
. 为方便起见,头文件包含所有命令代码的定义。
使用一个数据字节调用命令(通常写入寄存器):
void nrf24_writeReg(uint8_t cmd, uint8_t value);
如果我们没有单向 SPI 配置,我们也可以读取寄存器:
uint8_t nrf24_readReg(uint8_t cmd);
参数 cmd 包含作为单个字节的复合寄存器地址:如果读取,则为 1 并且00wAAAAA
是寄存器地址(第 9 章 - 寄存器映射)。w
AAAAA
写入 TX 缓冲区和多字节寄存器:
void nrf24_writeRegs(uint8_t cmd, const uint8_t *buff, uint8_t size);
如果我们不使用单向 SPI 配置,读取缓冲区的函数:
void nrf24_readRegs(uint8_t cmd, uint8_t *buff, uint8_t size);
参数列表是不言自明的。最后一组 API 函数用于在一段时间内“切换”CE 信号:
void nrf24_pulseCE(void);
这将在 CE 上产生大约 15us 的脉冲。该功能用于在无线电通电且 TX 缓冲区充满数据后切换到 TX 模式。
为了使 CE 保持较高的持续时间(通常在使用共享 CE/CSN 配置时用于 RX 模式),应使用以下函数:
void nrf24_pulseCE_ms(uint16_t milliseconds);
如果我们不与 CSN 共享 CE(单独连接),则由应用程序逻辑来控制 CE 引脚。
该库的存储库在main.c
文件中包含一个工作示例,用于通过 nRF24L01 驱动程序发送和接收 32 位序列号。
带 ATtiny13A 的发射器
发射器结合了第一个(共享 CE/CSN)和第三个(单向)硬件配置。这占用了 MCU 上的 3 个引脚,剩下 2 个(如果没有 RST,则为 +1)用于其他设备/传感器/应用程序。在我们的例子中,我们将一个红色 LED 连接到 PB3:
应用程序每 2 秒递增一次,并向通道 120 上的管道 0 发送一个 32 位无符号整数。LED 亮起 800 毫秒以指示周期的开始。源代码展示了从对讲机上电、配置模块、将数据移入缓冲区、传输和对讲机电源的整个过程。
包括为 nRF24 设计的库在内的发射器应用程序的总体占用空间为372 字节(可用 1KiB)和 6 字节 SRAM(共 64 字节)。
带 ATtiny13A 的接收器
接收器应用程序不使用共享 CE/CSN,因为该模块仅在 RX 模式下工作并且不传输数据(确认数据包除外)。为了优化引脚数,我们应用了总共占用 3 个 MCU 引脚的 3 线 SPI:
应用软件每 100 毫秒汇集一次状态寄存器以获取新数据包。如果数据包到达,则将其读入 MCU,并清除状态。如果接收到的序列号与前一个序列号的增量相同,则绿色 LED 亮 1 秒。
包括为 nRF24 设计的库在内的接收器应用程序的总体占用空间为420字节(可用 1KiB)和 6 字节 SRAM(共 64 字节)。
运行演示应用程序
同时运行发射器和接收器:
如果接收器接收到预期的序列号,接收器的 LED(绿色)将亮起 1 秒。红色 (TX) 和绿色 (RX) LED 之间的最大延迟约为 100 毫秒,这是由 RX 侧的池化引起的。
提议的 nRF24 库的主要目标和成就是:
然而,实现给定的目标需要付出一定的代价。API 提供的低粒度方法不如RF24 库或类似库中的高级方法方便。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !