Arduino 上利用 AVR TWI 硬件地址匹配实现从机主动上报的免轮询方案
👁 8 阅读 · 2026-08-31 · 嵌入式
在嵌入式系统中,I2C 从机通常被动等待主机查询,导致实时性差且总线占用高。本文介绍一种基于 AVR TWI 硬件地址匹配的创新方案:通过配置从机地址掩码和中断,使从机在特定事件发生时主动占用总线并向主机发送数据,实现免轮询的主动上报。文章详细讲解 TWI 地址匹配原理、寄存器配置、Arduino 代码实现及注意事项,帮助开发者提升系统响应效率。
# 引言
在典型的 I2C 通信中,从机只能被动响应主机请求,若需上报状态,主机必须周期性轮询,造成总线拥堵和响应延迟。AVR 系列单片机(如 ATmega328P)的 TWI(Two-Wire Interface)模块提供了硬件地址匹配功能,可扩展出“从机主动上报”模式。本文将深入剖析其原理,并给出在 Arduino 环境下的完整实现。
# TWI 硬件地址匹配原理
AVR 的 TWI 模块在硬件层面持续监听总线,并将接收到的地址字节与自身地址寄存器(TWAR)比较。当匹配成功时,硬件自动应答 ACK,并触发 TWI 中断(TWINT 置位)。关键点在于:
- **地址掩码寄存器(TWAMR)**:允许屏蔽地址位,使从机能响应多个地址。例如,设置 TWAMR=0xFE,则只匹配最低位,可响应两个地址。
- **通用调用地址(0x00)**:若启用,可被所有从机响应。
利用这些特性,我们可以设计一个“事件触发地址”:主机平时不轮询,但当从机需要上报时,它先通过 GPIO 拉低 SCL 或使用专用信号线通知主机,然后主机发送一个特定地址(如 0x55),从机通过地址匹配中断唤醒,并立即接管总线发送数据。但更优雅的做法是:从机直接利用 TWI 的“多主机”能力,在事件发生时主动发起传输。
# 免轮询方案设计
我们的目标是:从机在内部事件(如传感器阈值)发生时,主动向主机发送数据,而无需主机轮询。实现思路如下:
1. **初始化 TWI 为从机模式**,并设置一个“唤醒地址”(如 0x30)。
2. **启用 TWI 地址匹配中断**,但平时不响应任何地址(通过 TWAR 设置为不匹配地址)。
3. **当事件发生时**,从机临时修改 TWAR 为唤醒地址,并拉低 SCL 线(模拟总线占用)或直接发送 START 条件(多主机模式)。
4. **主机检测到总线活动**,发送唤醒地址,从机匹配后进入中断,此时从机切换为主机模式,发送数据。
但更简洁的免轮询方案是:从机在事件发生时,主动发送 START 并抢占总线(多主机模式),直接向主机地址发送数据。这需要从机支持多主机仲裁。AVR TWI 硬件支持多主机,但需谨慎处理总线冲突。
# 配置步骤
## 1. TWI 从机模式初始化
```c
#include
#include
void twi_slave_init(uint8_t addr) {
TWAR = addr << 1; // 设置从机地址(7位左移一位)
TWCR = (1<
#include
#include
#define EVENT_PIN 2
#define WAKE_ADDR 0x55
#define SELF_ADDR 0x30
volatile bool event_occurred = false;
volatile bool wake_received = false;
void setup() {
pinMode(EVENT_PIN, OUTPUT);
digitalWrite(EVENT_PIN, HIGH); // 空闲高电平
// 初始化 TWI 从机,地址设为不匹配
TWAR = 0x00; // 不响应任何地址
TWCR = (1<