我想使用Arduino作为i2c奴隶 . 但我要求Arduino通过向多个i2c地址注册来充当多个设备 .
这可能不是人们通常会做的事情,但这是我做这件事的原因:
我想用Arduino作为Spektrum遥测的遥测传感器 . 遥测接收器有一些i2c插头,连接到多个传感器(电流0x02,电压0x03,空速0x11等),每个传感器都具有遥测接收器所需的固定i2c地址 .
我想使用 one Arduino作为所有这些设备,通过注册所有上述地址,并适当地回应读数 .
我可以使用每个传感器一个Arduino,这看起来很傻,因为我可以使用一个Arduino pro-mini执行所有这些读数 .
我知道你可以使用注册Arduino
Wire.begin(0x02);
但是我需要类似的东西(伪代码)
Wire.begin(0x02, 0x03, 0x11);
当收到请求时,我需要知道Arduino被查询的地址 .
例如(伪代码)
void receiveEvent(byte address, int bytesReceived){
if(address == 0x02){
// Current reading
}
else if(address == 0x03){
// Voltage reading
}
else if(address == 0x11){
// Airspeed reading
}
}
任何意见,将不胜感激 .
5 回答
由于Wire.begin()仅允许传递单个从地址,因此无法通过使用Wire库使Arduino监听多个从地址 .
即使是大多数Arduinos所基于的Atmel ATmega微控制器也只允许其硬件2线串行接口(TWI)通过其2线地址寄存器
TWAR
设置为单个7位地址 . 然而,有可能通过使用TWI地址掩码寄存器TWAMR
屏蔽一个或多个地址位来解决这个限制,如在文献中(稍微简要地)所述 . 这是ATmega datasheet第22.9.6节:因此,我们首先必须根据我们要响应的所有I2C地址来设置掩码位,方法是对它们进行“或”运算并向右移动以匹配
TWAMR
寄存器布局(TWAMR
在bit7:1中保持掩码,bit0未使用):这里的主要问题是找出查询的特定I2C地址(我们只知道它与地址掩码匹配) . 如果我正确解释第22.5.3节,说明
我们应该能够从
TWDR
寄存器中检索未屏蔽的I2C地址 .ATmega TWI操作是基于中断的,更具体地说,它利用单个中断向量来处理由
TWSR
状态寄存器中的状态代码指示的过多的不同TWI事件 . 在TWI中断服务程序中,我们必须这样做确保我们查询原因的原因 . 这可以通过检查
TWSR
获取状态代码0xA8
(已收到自己的SLA R)来完成通过检查
TWDR
中总线上的最后一个字节,根据实际查询的I2C地址决定将哪些传感器数据发送回主站 .ISR的这一部分可能看起来像这样(未经测试):
感谢您提出这个有趣的问题!
我真的很喜欢vega8的答案,但我还想提一下,如果您的I2C主控制器不能快速计时,那么使用基于软件的I2C实现也是可行的,并为您提供所需的自由 .
如果粗略计算显示在TWI ISR中花费的时间太长并且中断可能开始重叠,则可能需要考虑该方法 .
这适用于带有遥测模块的Spectrum DX8 . Spectrum界面在Sectrums主页上公开 . 技术文件 .
I2C总线上可能有其他器件,TWAMR应设置尽可能少的位 . 所以我认为计算面具的更好方法是:
而TWAR可以设置为AddrOr或AddrAnd这样我们就可以将地址冲突的可能性限制在最小