如何使用Adafuit mcp23017.h库与多个mcp23017芯片?

7
我一直在尝试使用I2C和mcp23017 IO扩展芯片来控制我的Arduino ATMega2560,因为我希望将Arduino自身的IO用于其他事情。我正在努力学习如何使用adafruit mcp23017.h库,并且无法解决如何寻址多个mcp23017芯片和如何单独使用它们的引脚问题。这是我编辑的按钮库代码。
我想要能够寻址各个芯片和引脚,但不确定在设置过程中,如果连接了并在代码中寻址了多个芯片,IO的引脚模式是否会按顺序从0逐渐上升到15.例如,如果第一个芯片的地址为0x20并且IO号码计数从0-15,则如果我添加并寻址另一个芯片为0x21,计数是否会从0-15增加到0-31。
#include <Wire.h>
#include "Adafruit_MCP23017.h"

//pin 1 and 0 are mcp pins not arduino IO pins

Adafruit_MCP23017 mcp;

void setup() {  
mcp.begin();      // use default address 0

mcp.pinMode(0, INPUT);
mcp.pinMode(1, OUTPUT);
Serial.begin(9600);

pinMode(13, OUTPUT);  // use the p13 LED as debugging
}



void loop() {
// The LED will 'echo' the button
digitalWrite(13, mcp.digitalRead(0)); //Writes pin 13 to the reading of pin    0
mcp.digitalWrite(1, mcp.digitalRead(0)); //Writes pin 1 to the reading of 0
if(mcp.digitalRead(1) == HIGH){ //if pin 1 == high serialprint led whent   high
Serial.println("Led whent HIGH");
}
}

我不知道如何将芯片称为0x20或0x21。查看库的头文件代码,似乎将默认地址设置为0x20。 - ChrisPlusPlus
好的,我以前从未在Arduino上使用过MCP23017芯片,但在树莓派上,使用“i2c-tools”软件包中的“i2cset”命令手动写入到控制Bank A和Bank B方向的输入/输出寄存器非常容易。 然后,您可以在一次写操作/一个字节中设置或读取任意一侧的所有引脚。无论如何,请检查这行代码:“mcp.begin(); //使用默认地址0”。它给我留下了印象,您可以向“mcp.begin()”提供一个数字/地址;例如,“mcp.begin(0x20);”或“mcp.begin(32);” - jDo
1
void Adafruit_MCP23017::begin(uint8_t addr) <-- 在这里,您可以提供一个地址来覆盖默认值(0)。从Adafruit_MCP23017.cpp中得知,它使用十进制0-7作为地址,而不是十六进制。 mcp.begin(0x20) 应该是 mcp.begin(0)mcp.begin(1)等等。 - jDo
我应该将"void Adafruit_MCP23017::begin(uint8_t addr)"实现到头文件还是实际代码中呢?我有点困惑,因为我对Arduino还很陌生。 - ChrisPlusPlus
就像 Vladimir Tsykunov 所说的“默认情况下,该库不支持多个芯片”,因此我现在认为添加这个功能不会有太大帮助,反而会让整个代码更加混乱。 - ChrisPlusPlus
显示剩余6条评论
3个回答

6
每个芯片必须具有唯一的地址,根据Microchip手册第8页的说明可以实现。因此,首先应在硬件布局中设置不同的地址。
您还应为要使用的每个芯片创建一个Adafruit_MCP23017对象,并在代码中设置相应的地址。
在这种情况下,所有芯片的引脚地址将在0-15范围内。要更改引脚状态,您应该引用特定实例。

更新

这是您的起点

#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp1;
Adafruit_MCP23017 mcp2;
Adafruit_MCP23017 mcp3;
#define addr1 0x00
#define addr2 0x01
#define addr3 0x02
void setup() {
 mcp1.begin(addr1);
 mcp2.begin(addr2);
 mcp3.begin(addr3);
}

void loop() {


}

当你说 "最后一个是,你应该为每个你想使用的芯片创建一个Adafruit_MCP23017对象,并在代码中设置相应的地址。" 时,你的意思是创建还是复制现有的类?如果是这样,我仍然不清楚我要调整什么? - ChrisPlusPlus
1
我用mcp1(0)然后mcp2(1)让它工作了,它需要的是十进制值而不是十六进制。 - ChrisPlusPlus
1
是的,现在清楚了。虽然物理地址从0x20开始,但是Adafruit将0-> 0x20,1-> 0x21等进行转换。 - Vladimir Tsykunov
1
@ jDo,这里没有十六进制、十进制或八进制数字,它们只是数字,无论你使用哪种表示法都可以。所以,是的,0x01等于1。 - Vladimir Tsykunov
@jDo支持7个芯片,因为mcp23017有3位用于存储用户地址[手册->第8页]。 - Vladimir Tsykunov
显示剩余7条评论

3

我使用7个MCP23017芯片,共计98个引脚,并使用adafruit库。以下是连接方法:

addr 0 = A2 low , A1 low , A0 low  000
addr 1 = A2 low , A1 low , A0 high 001
addr 2 = A2 low , A1 high , A0 low  010
addr 3 = A2 low , A1 high , A0 high  011
addr 4 = A2 high , A1 low , A0 low  100
addr 5 = A2 high , A1 low , A0 high  101
addr 6 = A2 high , A1 high , A0 low  110
addr 7 = A2 high, A1 high, A0 high 111

Connect pin #12 of the expander to Analog 5 (i2c clock)
Connect pin #13 of the expander to Analog 4 (i2c data)
Connect pins #15, 16 and 17 of the expander to ground (address selection)
Connect pin #9 of the expander to 5V (power) // operation voltage is 1.8 to 5.5
Connect pin #10 of the expander to ground (common ground)
Connect pin #18 through a ~10kohm resistor to 5V (reset pin, active low)

Input #0 is on pin 21 so connect a button or switch from there to ground

代码:

#include <Adafruit_MCP23017.h>


Adafruit_MCP23017 mcp1; // chip 1
Adafruit_MCP23017 mcp2; // chip 2

#define addr1 7 // 7 = A2 high, A1 high, A0 high
#define addr2 0 // 0 = A2 low, A1 low, A0 low
void setup() 
  {
    Serial.begin(9600); 
    mcp1.begin(addr1);
    mcp2.begin(addr2);

    mcp1.pinMode(0, INPUT); //pin 21 on chip
    mcp2.pinMode(0, INPUT); //pin 21 on chip

  } 

  void loop()
  { 
      if(mcp1.digitalRead(0)== HIGH )
      Serial.println("HIGH"); 
      delay(1000);

      if(mcp2.digitalRead(0)== HIGH )
      Serial.println("HIGH 2"); 
      delay(1000);
  }

1

我终于让我的代码工作了!最后它比我想象的要简单,而且我可能没有给出足够清晰的解释来说明我的代码的目的。这是我的代码:

#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp1;
Adafruit_MCP23017 mcp2;
void setup() {
mcp1.begin(0);
mcp2.begin(1);

mcp1.pinMode(0, INPUT);
mcp1.pinMode(1, OUTPUT);
mcp2.pinMode(1, OUTPUT);
Serial.begin(9600);
pinMode(13, OUTPUT);
}

void loop() {
mcp2.digitalWrite(1, mcp1.digitalRead(0));
digitalWrite(13, mcp1.digitalRead(0));
mcp1.digitalWrite(1, mcp1.digitalRead(0));
if(mcp1.digitalRead(1) == HIGH){
Serial.println("Led whent HIGH");
}
}

问题在于我只声明了一个mcp,感谢Vladimir Tsykunov,现在我知道我需要一个mcp1和mcp2,在我的功能代码中可以看到。未来可能会遇到一些我没有修改的问题,但对于这个项目,现在它正在工作。

我完全不同意库等待十进制或十六进制,这是错误的。库不期望某些特定的数字表示。您在代码中使用十六进制或十进制,这是您表示数字的方式。它不会传递到硬件或汇编代码。处理器使用包含二进制零和一的寄存器。例如:'10' 十进制 = 'A' 十六进制 = '12' 八进制,但对于处理器核心仍然是 b1010。 - Vladimir Tsykunov
所以我的代码是正确的,但我对代码的理解被误解了吗?因为当我添加mcp2.begin(1);并将芯片地址设置为那个时,它似乎可以工作,但是当我使用mcp2.begin(addr2);或mcp2.begin(0x21);时,它就不起作用了。我知道如果要使第一个工作,我需要将addr2定义为0x21,但即使这样,它仍然不起作用。 - ChrisPlusPlus
1
@ChrisPlusPlus "感谢 jDo 告诉我需要使用十进制数而不是十六进制数" 仅仅为了澄清一下,除了让总线上芯片数量出现混淆(抱歉),我提供的信息是:1-你可以向 mcp.begin() 提供一个参数;2-这些参数不是实际的、物理的总线地址,如果你手动写入芯片,你会用到它们(它们从32/0x20开始)。相反,该库使用的是0-7。我只是不想因为说十六进制1与十进制1不同而被记录下来:D - jDo
好的,我刚才有些误解,可能有点累了。但是你仍然帮助我调整了一些我不确定的东西,并让它正常工作。我认为我们可以把这个问题搁置了,除非你还有其他想要补充的内容。 :) - ChrisPlusPlus
@ChrisPlusPlus 听起来不错 :) 祝你编程愉快! - jDo
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接