Forum: Mikrocontroller und Digitale Elektronik MCP23017 - Einzelne Pins auf High schalten


von Elektron (Gast)


Lesenswert?

Schönen guten Abend,
ich habe mir vor kurzem vorgenommen, für den MCP23017 mir eine eigene 
Library zu schreiben, da ich auch verstehen möchte, wie der Chip 
angesprochen wird, habe bis dato die Library von der Seite benutzt: 
http://arduino.alhin.de/index.php?n=83

klappt soweit auch ganz gut aber wie gesagt, ich möchte es selber 
schreiben.

ich habe soweit auch alles hin bekommen, nur ich bekomme einen 
eigentlich ganz simplen befehl nicht hin:

in der vorhandenen Lib ist es so:
1
mcp.digitalWrite(i, HIGH);
 wenn man den pin i high schalten möchte

ich bekomme es nur so hin:
1
 Wire.write(0x12); // GPIOA
1
 Wire.write(i); // port A

aber damit schalte ich ja alle ports bzw schalte ich die ports quasi 
binär auf die werte 0 - 255

wie aber bekomme ich es aber hin, es nicht binär sondern einen pin zu 
schalen, ohne andere pin werte abzufragen / ein zuberechen bzw zu 
beeinflussen.

ich habe mir die fertige Library angeguckt aber werde nicht schlauer, 
wie die es gemacht haben. eigentlich muss doch jeder pin ne eigene 
adresse haben, oder sehe ich das falsch.

von Samuel C. (dragonsam)


Lesenswert?


von Elektron (Gast)


Lesenswert?

Oweia, kann man das nicht anders lösen? Wenn ich doch beim uC sagen Pin 
1 High, dann geht das doch auch ohne Bit Manipulation

von Max H. (hartl192)


Lesenswert?

Bei Arduino gehts auch ohne Wissen über den uC. Irgendwo steckt sicher 
die Bitmanipulation, sie ist für dich aber nicht sichtbar.
Ich kenne den MCP nicht, wenn er keine Funktion zum setzen einzelner 
Bits hat würde ich den MCP auslesen, das Bit ändern und die geänderten 
Daten wider zurückschreiben.

von Elektron (Gast)


Lesenswert?

Max H. schrieb:
> Bei Arduino gehts auch ohne Wissen über den uC. Irgendwo steckt
> sicher die Bitmanipulation, sie ist für dich aber nicht sichtbar.
> Ich kenne den MCP nicht, wenn er keine Funktion zum setzen einzelner
> Bits hat würde ich den MCP auslesen, das Bit ändern und die geänderten
> Daten wider zurückschreiben.

Ich bin mir nicht sicher, da ich beim Datenblatt leichte Probleme habe. 
Gibt's hier den niemand, der den MCP einsetzt?

von tomske (Gast)


Lesenswert?

Die Lösungen, die ich bislang gesehen hab, merken sich die komplette 
Belegung der Ausgänge als lokalen Zustand (z.B als data member in der 
Klasse), manipulieren diese mittels der angesprochenen 
Bitmanipulationen, und schreiben den kompletten lokalen Zustand der 
Ausgänge dann per SPI in den MCP27017. Man könnte den Zustand auch 
abfragen, manipulieren und zurückschreiben, das dauert aber länger und 
ist unnötig.

Hilft Dir das weiter?
Tomske

von Samuel C. (dragonsam)


Lesenswert?

Bitmanipulation ist die gängige Methode. Nur weil du das bei deinem 
Arduino-Code nicht sehen kannst, heißt das noch lange nicht, dass das 
nicht genauso gehandhabt wird. Ruf mal die Funktion auf, dann siehst du 
wie sie funktioniert. Ich bin mir ziemlich sicher, dass dort nichts 
anderes gemacht wird.

tomske schrieb:
> Die Lösungen, die ich bislang gesehen hab, merken sich die
> komplette
> Belegung der Ausgänge als lokalen Zustand (z.B als data member in der
> Klasse), manipulieren diese mittels der angesprochenen
> Bitmanipulationen, und schreiben den kompletten lokalen Zustand der
> Ausgänge dann per SPI in den MCP27017. Man könnte den Zustand auch
> abfragen, manipulieren und zurückschreiben, das dauert aber länger und
> ist unnötig.

1. Ob man eine lokale Variable manipuliert oder den Wert eines 
Port-Register sieht macht keinen Unterschied im Code.

2. Ob man eine lokale Variable manipuliert oder den Wert eines 
Port-Register sieht macht keinen zeitlichen Unterschied. Vom 
Port-Register hat man den Wert genau so schnell, wie vom RAM, eventuell 
sogar schneller.

von Flex (Gast)


Lesenswert?

[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
 ****************************************************/

#include <Wire.h>
#include <avr/pgmspace.h>
#include "Adafruit_MCP23017.h"

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

// minihelper
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
}

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

void Adafruit_MCP23017::begin(uint8_t addr) {
  if (addr > 7) {
    addr = 7;
  }
  i2caddr = addr;

  Wire.begin();


  // set defaults!
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_IODIRA);
  wiresend(0xFF);  // all inputs on port A
  Wire.endTransmission();

  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_IODIRB);
  wiresend(0xFF);  // all inputs on port B
  Wire.endTransmission();
}


void Adafruit_MCP23017::begin(void) {
  begin(0);
}

void Adafruit_MCP23017::pinMode(uint8_t p, uint8_t d) {
  uint8_t iodir;
  uint8_t iodiraddr;

  // only 16 bits!
  if (p > 15)
    return;

  if (p < 8)
    iodiraddr = MCP23017_IODIRA;
  else {
    iodiraddr = MCP23017_IODIRB;
    p -= 8;
  }

  // read the current IODIR
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(iodiraddr);
  Wire.endTransmission();

  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  iodir = wirerecv();

  // set the pin and direction
  if (d == INPUT) {
    iodir |= 1 << p;
  } else {
    iodir &= ~(1 << p);
  }

  // write the new IODIR
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(iodiraddr);
  wiresend(iodir);
  Wire.endTransmission();
}

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;
}

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 p, uint8_t d) {
  uint8_t gpio;
  uint8_t gpioaddr, olataddr;

  // only 16 bits!
  if (p > 15)
    return;

  if (p < 8) {
    olataddr = MCP23017_OLATA;
    gpioaddr = MCP23017_GPIOA;
  } else {
    olataddr = MCP23017_OLATB;
    gpioaddr = MCP23017_GPIOB;
    p -= 8;
  }

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

  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
   gpio = wirerecv();

  // set the pin and direction
  if (d == HIGH) {
    gpio |= 1 << p;
  } else {
    gpio &= ~(1 << p);
  }

  // write the new GPIO
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gpioaddr);
  wiresend(gpio);
  Wire.endTransmission();
}

void Adafruit_MCP23017::pullUp(uint8_t p, uint8_t d) {
  uint8_t gppu;
  uint8_t gppuaddr;

  // only 16 bits!
  if (p > 15)
    return;

  if (p < 8)
    gppuaddr = MCP23017_GPPUA;
  else {
    gppuaddr = MCP23017_GPPUB;
    p -= 8;
  }


  // read the current pullup resistor set
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gppuaddr);
  Wire.endTransmission();

  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  gppu = wirerecv();

  // set the pin and direction
  if (d == HIGH) {
    gppu |= 1 << p;
  } else {
    gppu &= ~(1 << p);
  }

  // write the new GPIO
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gppuaddr);
  wiresend(gppu);
  Wire.endTransmission();
}

uint8_t Adafruit_MCP23017::digitalRead(uint8_t p) {
  uint8_t gpioaddr;

  // only 16 bits!
  if (p > 15)
    return 0;

  if (p < 8)
    gpioaddr = MCP23017_GPIOA;
  else {
    gpioaddr = MCP23017_GPIOB;
    p -= 8;
  }

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

  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  return (wirerecv() >> p) & 0x1;
}

[/C]

Ich muss dem Thread Ersteller aber recht geben, ich finde hier auch 
nichts davon.

von Samuel C. (dragonsam)


Lesenswert?

Flex schrieb:
> void Adafruit_MCP23017::digitalWrite(uint8_t p, uint8_t d) {
>
>   [ ... ]
>
>   // set the pin and direction
>   if (d == HIGH) {
>     gpio |= 1 << p;
>   } else {
>     gpio &= ~(1 << p);
>   }
>
>   [ ... ]
>
> }

Rate mal, was das ist ;)

Edit: Ok, mir war nicht klar, dass es hier um einen Portexpander geht. 
Dann spart eine Variable mit dem Port-Inhalt natürlich schon Zeit, aber 
um Bitmanipulation kommst du nicht rum.

: Bearbeitet durch User
von tomske (Gast)


Lesenswert?

> 2. Ob man eine lokale Variable manipuliert oder den Wert eines
> Port-Register sieht macht keinen zeitlichen Unterschied. Vom
> Port-Register hat man den Wert genau so schnell, wie vom RAM, eventuell
> sogar schneller.

Die Port-Register, um die es geht, sind im MCP23017. Also kann man den 
Baustein per SPI befragen, welche Belegung die Ausgänge gerade haben, 
dann den gewünschten Ausgang lokal manipulieren und das Ergebnis zurück 
auf den Baustein senden (wieder per SPI).

Ich sehe diese Schritte im Code oben wieder:
1
// read the current GPIO output latches
2
...
3
// set the pin and direction
4
...
5
// write the new GPIO


Das Auslesen kann man sich sparen, weil man in der Regel lokal auf dem 
Prozessor wissen kann (wenn man sich den Zustand merkt), wie die 
Ausgänge stehen.

Grüße
Tomske

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.