Forum: Mikrocontroller und Digitale Elektronik MCP23017 ESP 8266 Interrupt?


von Tobi (Gast)


Lesenswert?

Hallo,

ich steige grad auf ESP8266 und Arduino Sketch um. Hab einen FC103 I2C 
Expander und die MP23017 Lib.

Funktioniert auf alles ganz gut, nur das der Pin 0x02 am Expander 
"""eine Art Interrupt """ auswirft sobald der Pin toggelt.
Kann man das irgendwo in der Lib ändern ? Abschalten ? auf einen anderen 
Pin legen ? Irgendwas ? möchte ungern die Hardware ändern.






#include <Wire.h>
#include "Adafruit_MCP23017.h"

#define RELAIS_1 0x06
#define RELAIS_2 0x07
#define RELAIS_3 0x05
#define RELAIS_4 0x02
#define RELAIS_5 0x00
#define RELAIS_6 0x01
#define _pause 2000



Adafruit_MCP23017 Relaiskarte;

void setup()
{
  Relaiskarte.begin(6);      // use default address 26
  Relaiskarte.pinMode(RELAIS_1, OUTPUT);
  Relaiskarte.pinMode(RELAIS_2, OUTPUT);
  Relaiskarte.pinMode(RELAIS_3, OUTPUT);
  Relaiskarte.pinMode(RELAIS_4, OUTPUT);
  Relaiskarte.pinMode(RELAIS_5, OUTPUT);
  Relaiskarte.pinMode(RELAIS_6, OUTPUT);

  }

void loop()
{

  Relaiskarte.digitalWrite(RELAIS_6, HIGH);
  delay(_pause);
  Relaiskarte.digitalWrite(RELAIS_6, LOW);
  delay(_pause);
}


Jedes mal wenn irgendwas schaltet, ""wischt"" Relais_4 kurz mit...

...h

/***************************************************
  This is a library for the MCP23017 i2c port expander

  These displays use I2C to communicate, 2 pins are required to
  interface
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#ifndef Adafruit_MCP23017_H
#define Adafruit_MCP23017_H

// Don't forget the Wire library
#ifdef _AVR_ATtiny85_
#include <TinyWireM.h>
#else
#include <Wire.h>
#endif

class Adafruit_MCP23017 {
public:
  void begin(uint8_t addr);
  void begin(void);

  void pinMode(uint8_t p, uint8_t d);
  void digitalWrite(uint8_t p, uint8_t d);
  void pullUp(uint8_t p, uint8_t d);
  uint8_t digitalRead(uint8_t p);

  void writeGPIOAB(uint16_t);
  uint16_t readGPIOAB();
  uint8_t readGPIO(uint8_t b);

  void setupInterrupts(uint8_t mirroring, uint8_t open, uint8_t 
polarity);
  void setupInterruptPin(uint8_t p, uint8_t mode);
  uint8_t getLastInterruptPin();
  uint8_t getLastInterruptPinValue();

 private:
  uint8_t i2caddr;

  uint8_t bitForPin(uint8_t pin);
  uint8_t regForPin(uint8_t pin, uint8_t portAaddr, uint8_t portBaddr);

  uint8_t readRegister(uint8_t addr);
  void writeRegister(uint8_t addr, uint8_t value);

  /**
   * Utility private method to update a register associated with a pin 
(whether port A/B)
   * reads its value, updates the particular bit, and writes its value.
   */
  void updateRegisterBit(uint8_t p, uint8_t pValue, uint8_t portAaddr, 
uint8_t portBaddr);

};

#define MCP23017_ADDRESS 0x20

// registers
#define MCP23017_IODIRA 0x00
#define MCP23017_IPOLA 0x02//voher 02
#define MCP23017_GPINTENA 0x04//vorher 04
#define MCP23017_DEFVALA 0x06
#define MCP23017_INTCONA 0x08
#define MCP23017_IOCONA 0x0A
#define MCP23017_GPPUA 0x0C
#define MCP23017_INTFA 0x0E
#define MCP23017_INTCAPA 0x10
#define MCP23017_GPIOA 0x04
#define MCP23017_OLATA 0x14


#define MCP23017_IODIRB 0x01
#define MCP23017_IPOLB 0x03
#define MCP23017_GPINTENB 0x05//vorher05
#define MCP23017_DEFVALB 0x07
#define MCP23017_INTCONB 0x09
#define MCP23017_IOCONB 0x0B
#define MCP23017_GPPUB 0x0D
#define MCP23017_INTFB 0x0F
#define MCP23017_INTCAPB 0x11
#define MCP23017_GPIOB 0x05
#define MCP23017_OLATB 0x15

#define MCP23017_INT_ERR 255

#endif



...c

/***************************************************
 This is a library for the MCP23017 i2c port expander

 These displays use I2C to communicate, 2 pins are required to
 interface
 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 Written by Limor Fried/Ladyada for Adafruit Industries.
 BSD license, all text above must be included in any redistribution
 ****************************************************/

#ifdef _AVR_ATtiny85_
  #include <TinyWireM.h>
  #define Wire TinyWireM
#else
  #include <Wire.h>
#endif


#ifdef __AVR
  #include <avr/pgmspace.h>
#elif defined(ESP8266)
  #include <pgmspace.h>
#endif
#include "Adafruit_MCP23017.h"

#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// minihelper to keep Arduino backward compatibility
static inline void wiresend(uint8_t x) {
#if ARDUINO >= 100
  Wire.write((uint8_t) x);
#else
  Wire.send(x);
#endif
}

static inline uint8_t wirerecv(void) {
#if ARDUINO >= 100
  return Wire.read();
#else
  return Wire.receive();
#endif
}

/**
 * Bit number associated to a give Pin
 */
uint8_t Adafruit_MCP23017::bitForPin(uint8_t pin){
  return pin%8;
}

/**
 * Register address, port dependent, for a given PIN
 */
uint8_t Adafruit_MCP23017::regForPin(uint8_t pin, uint8_t portAaddr, 
uint8_t portBaddr){
  return(pin<8) ?portAaddr:portBaddr;
}

/**
 * Reads a given register
 */
uint8_t Adafruit_MCP23017::readRegister(uint8_t addr){
  // read the current GPINTEN
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(addr);
  Wire.endTransmission();
  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  return wirerecv();
}


/**
 * Writes a given register
 */
void Adafruit_MCP23017::writeRegister(uint8_t regAddr, uint8_t 
regValue){
  // Write the register
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(regAddr);
  wiresend(regValue);
  Wire.endTransmission();
}


/**
 * Helper to update a single bit of an A/B register.
 * - Reads the current register value
 * - Writes the new register value
 */
void Adafruit_MCP23017::updateRegisterBit(uint8_t pin, uint8_t pValue, 
uint8_t portAaddr, uint8_t portBaddr) {
  uint8_t regValue;
  uint8_t regAddr=regForPin(pin,portAaddr,portBaddr);
  uint8_t bit=bitForPin(pin);
  regValue = readRegister(regAddr);

  // set the value for the particular bit
  bitWrite(regValue,bit,pValue);

  writeRegister(regAddr,regValue);
}

//////////////////////////////////////////////////////////////////////// 
////////

/**
 * Initializes the MCP23017 given its HW selected address, see datasheet 
for Address selection.
 */
void Adafruit_MCP23017::begin(uint8_t addr) {
  if (addr > 7) {
    addr = 7;
  }
  i2caddr = addr;

  Wire.begin();

  // set defaults!
  // all inputs on port A and B
  writeRegister(MCP23017_IODIRA,0xff);
  writeRegister(MCP23017_IODIRB,0xff);
}

/**
 * Initializes the default MCP23017, with 000 for the configurable part 
of the address
 */
void Adafruit_MCP23017::begin(void) {
  begin(0);
}

/**
 * Sets the pin mode to either INPUT or OUTPUT
 */
void Adafruit_MCP23017::pinMode(uint8_t p, uint8_t d) {
  updateRegisterBit(p,(d==INPUT),MCP23017_IODIRA,MCP23017_IODIRB);
}

/**
 * Reads all 16 pins (port A and B) into a single 16 bits variable.
 */
uint16_t Adafruit_MCP23017::readGPIOAB() {
  uint16_t ba = 0;
  uint8_t a;

  // read the current GPIO output latches
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_GPIOA);
  Wire.endTransmission();

  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 2);
  a = wirerecv();
  ba = wirerecv();
  ba <<= 8;
  ba |= a;

  return ba;
}

/**
 * Read a single port, A or B, and return its current 8 bit value.
 * Parameter b should be 0 for GPIOA, and 1 for GPIOB.
 */
uint8_t Adafruit_MCP23017::readGPIO(uint8_t b) {

  // read the current GPIO output latches
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  if (b == 0)
    wiresend(MCP23017_GPIOA);
  else {
    wiresend(MCP23017_GPIOB);
  }
  Wire.endTransmission();

  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  return wirerecv();
}

/**
 * Writes all the pins in one go. This method is very useful if you are 
implementing a multiplexed matrix and want to get a decent refresh rate.
 */
void Adafruit_MCP23017::writeGPIOAB(uint16_t ba) {
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_GPIOA);
  wiresend(ba & 0xFF);
  wiresend(ba >> 8);
  Wire.endTransmission();
}

void Adafruit_MCP23017::digitalWrite(uint8_t pin, uint8_t d) {
  uint8_t gpio;
  uint8_t bit=bitForPin(pin);


  // read the current GPIO output latches
  uint8_t regAddr=regForPin(pin,MCP23017_OLATA,MCP23017_OLATB);
  gpio = readRegister(regAddr);

  // set the pin and direction
  bitWrite(gpio,bit,d);

  // write the new GPIO
  regAddr=regForPin(pin,MCP23017_GPIOA,MCP23017_GPIOB);
  writeRegister(regAddr,gpio);
}

void Adafruit_MCP23017::pullUp(uint8_t p, uint8_t d) {
  updateRegisterBit(p,d,MCP23017_GPPUA,MCP23017_GPPUB);
}

uint8_t Adafruit_MCP23017::digitalRead(uint8_t pin) {
  uint8_t bit=bitForPin(pin);
  uint8_t regAddr=regForPin(pin,MCP23017_GPIOA,MCP23017_GPIOB);
  return (readRegister(regAddr) >> bit) & 0x1;
}

/**
 * Configures the interrupt system. both port A and B are assigned the 
same configuration.
 * Mirroring will OR both INTA and INTB pins.
 * Opendrain will set the INT pin to value or open drain.
 * polarity will set LOW or HIGH on interrupt.
 * Default values after Power On Reset are: (false,flase, LOW)
 * If you are connecting the INTA/B pin to arduino 2/3, you should 
configure the interupt handling as FALLING with
 * the default configuration.
 */
void Adafruit_MCP23017::setupInterrupts(uint8_t mirroring, uint8_t 
openDrain, uint8_t polarity){
  // configure the port A
  uint8_t ioconfValue=readRegister(MCP23017_IOCONA);
  bitWrite(ioconfValue,6,mirroring);
  bitWrite(ioconfValue,2,openDrain);
  bitWrite(ioconfValue,1,polarity);
  writeRegister(MCP23017_IOCONA,ioconfValue);

  // Configure the port B
  ioconfValue=readRegister(MCP23017_IOCONB);
  bitWrite(ioconfValue,6,mirroring);
  bitWrite(ioconfValue,2,openDrain);
  bitWrite(ioconfValue,1,polarity);
  writeRegister(MCP23017_IOCONB,ioconfValue);
}

/**
 * Set's up a pin for interrupt. uses arduino MODEs: CHANGE, FALLING, 
RISING.
 *
 * Note that the interrupt condition finishes when you read the 
information about the port / value
 * that caused the interrupt or you read the port itself. Check the 
datasheet can be confusing.
 *
 */
void Adafruit_MCP23017::setupInterruptPin(uint8_t pin, uint8_t mode) {

  // set the pin interrupt control (0 means change, 1 means compare 
against given value);
  updateRegisterBit(pin,(mode!=CHANGE),MCP23017_INTCONA,MCP23017_INTCONB);
  // if the mode is not CHANGE, we need to set up a default value, 
different value triggers interrupt

  // In a RISING interrupt the default value is 0, interrupt is 
triggered when the pin goes to 1.
  // In a FALLING interrupt the default value is 1, interrupt is 
triggered when pin goes to 0.
  updateRegisterBit(pin,(mode==FALLING),MCP23017_DEFVALA,MCP23017_DEFVALB) 
;

  // enable the pin for interrupt
  updateRegisterBit(pin,HIGH,MCP23017_GPINTENA,MCP23017_GPINTENB);

}

uint8_t Adafruit_MCP23017::getLastInterruptPin(){
  uint8_t intf;

  // try port A
  intf=readRegister(MCP23017_INTFA);
  for(int i=0;i<8;i++) if (bitRead(intf,i)) return i;

  // try port B
  intf=readRegister(MCP23017_INTFB);
  for(int i=0;i<8;i++) if (bitRead(intf,i)) return i+8;

  return MCP23017_INT_ERR;

}
uint8_t Adafruit_MCP23017::getLastInterruptPinValue(){
  uint8_t intPin=getLastInterruptPin();
  if(intPin!=MCP23017_INT_ERR){
    uint8_t 
intcapreg=regForPin(intPin,MCP23017_INTCAPA,MCP23017_INTCAPB);
    uint8_t bit=bitForPin(intPin);
    return (readRegister(intcapreg)>>bit) & (0x01);
  }

  return MCP23017_INT_ERR;
}

von Karl M. (Gast)


Lesenswert?

Hi Tobi ,

was steht den im Datenblatt des MP23017?

http://ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf

Die Info kannst Du dir doch selbst besorgen.

von Tobi (Gast)


Lesenswert?

Hallo Karl,

ich hatte vergessen zu erwähnen das der Port Expander einen PCF8574 Chip 
hat...

von Michael U. (amiga)


Lesenswert?

Hallo,

und wo ist jetzt der Zusammenhang mit Deinem MCP23017 Code?

Gruß aus Berlin
Michael

von Tobi (Gast)


Lesenswert?

Hallo Michael,

die Lib wurde im Internet als passend beschrieben. Deshalb benutze ich 
sie.

Ich bin blutiger Anfänger ... deswegen ...

Nochmal das Problem : Egal welchen pin ich toggle, an P2 (PIN12) kommt 
immer ein Signal das ich am INT (PIN1) erwarten würde. Ich habe die 
Schaltung gefühlt 87 mal überprüft. Das Relais hängt am P2 !

Ich kann es auch ansteuern. Nur es reagiert eben auch wie ein Interrupt 
, wenn ich die anderen ansteuere. Für mich kommt als "Fehlerquelle" nur 
die Lib in Frage.
Ist sicher nur ein Fehler in der Anwendung. Aber ich komm nicht drauf...

Hat vielleicht hiermit was zu tun : Lib.c :

void Adafruit_MCP23017::setupInterrupts(uint8_t mirroring, uint8_t 
openDrain, uint8_t polarity){
  // configure the port A
  uint8_t ioconfValue=readRegister(MCP23017_IOCONA);
  bitWrite(ioconfValue,6,mirroring);
  bitWrite(ioconfValue,2,openDrain);
  bitWrite(ioconfValue,1,polarity);
  writeRegister(MCP23017_IOCONA,ioconfValue);

  // Configure the port B
  ioconfValue=readRegister(MCP23017_IOCONB);
  bitWrite(ioconfValue,6,mirroring);
  bitWrite(ioconfValue,2,openDrain);
  bitWrite(ioconfValue,1,polarity);
  writeRegister(MCP23017_IOCONB,ioconfValue);
}

/**
 * Set's up a pin for interrupt. uses arduino MODEs: CHANGE, FALLING, 
RISING.
 *
 * Note that the interrupt condition finishes when you read the 
information about the port / value
 * that caused the interrupt or you read the port itself. Check the 
datasheet can be confusing.
 *
 */
void Adafruit_MCP23017::setupInterruptPin(uint8_t pin, uint8_t mode) {

  // set the pin interrupt control (0 means change, 1 means compare 
against given value);
  updateRegisterBit(pin,(mode!=CHANGE),MCP23017_INTCONA,MCP23017_INTCONB);
  // if the mode is not CHANGE, we need to set up a default value, 
different value triggers interrupt

  // In a RISING interrupt the default value is 0, interrupt is 
triggered when the pin goes to 1.
  // In a FALLING interrupt the default value is 1, interrupt is 
triggered when pin goes to 0.
  updateRegisterBit(pin,(mode==FALLING),MCP23017_DEFVALA,MCP23017_DEFVALB) 
;

  // enable the pin for interrupt
  updateRegisterBit(pin,HIGH,MCP23017_GPINTENA,MCP23017_GPINTENB);

von Tobi (Gast)


Lesenswert?

z.B.:

P6 : _______--------________---------_______
P2 : _______-_______-_______-________-______

von Logik (Gast)


Lesenswert?

Denkst Du wirklich, dass eine Bibliothek für den MCP23017 auch für den 
PCF8574 paßt? Das sind zwei völlig verschiedene IC, die nur sehr wenig 
gemeinsam haben.

Tobi schrieb:
> die Lib wurde im Internet als passend beschrieben. Deshalb benutze ich
> sie.

Glaub ich nicht. Wo stand das?

von Tobi (Gast)


Lesenswert?

Find ich grad nicht wieder...

hatte ich schon erwähnt, das alles bis auf dieses kleine Problem 
einwandfrei funktioniert ?

von hp-feind (Gast)


Lesenswert?

@Tobi:
Lies erstmal das hier durch, bevor Du das Forum zumüllst:

http://www.mikrocontroller.net/articles/Formatierung_im_Forum

Danke.

von Tobi (Gast)


Lesenswert?

@hp-feind

also du weißt auch keine Lösung, wolltest dich aber trotzdem zu Wort 
melden ?

von Tobi (Gast)


Lesenswert?

Nur um das ganze zum Ende zu bringen :

Ich habe die Lib gewechselt. Und zwar auf :adafruit_MCP23008.h

Auch hier hatte ich anfangs ein ähnliches Problem. Nur diesmal an einem 
anderem Relais.
Nachdem ich in der .h das define geändert habe, läuft es wie gewünscht.

    #define MCP23008_GPIO 0x00//vorher09

Ob es technisch richtig ist oder nicht, soll mir erstmal egal sein. 
Hauptsache es funktioniert.
( Um Auto zu fahren, muss ich ja auch nicht wissen wissen wie das 
Motorsteuergerät funktioniert.)

Auslöser ist wohl die readGPIO() gewesen. Diese Funktion hat den P2 auf 
HIGH gesetzt. die digitalwrite() hat in sofort wieder auf LOW gesetzt. 
Somit entstand der Eindruck eines Interrupts.


Meinen besonderen Dank an hp-feind. Ohne deine konstruktiven 
Lösungsvorschläge hätte ich es nicht geschafft.


Allen noch einen schönen zweiten Weihnachtstag !
(außer hp-feind )

von Michael U. (amiga)


Lesenswert?

Hallo,

naja, einfach eine Lib für den PCF8574 zu nehmen wäre ja auch blöd 
gewesen...

Gruß aus Berlin
Michael

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.