MCP23017 - Abfrage Taster

Gast #5367502
Lesenswert?

Hallo
Zur Abfrage eines Tasters am MCP23017 habe ich folgenden Code:
1
 // einlesen der Port / Taster
2
      i2c_start(MCP23017_ADDR);    // Adresse
3
      i2c_write(MCP23017_GPIOB);
4
      Data = i2c_read(0xff);        // liest Ausgänge ein
5
      i2c_stop();
6
    
7
    if (Data == 0x01)
8
      {
9
      i2c_start(MCP23017_ADDR);    // Adresse
10
      i2c_write(MCP23017_OLATA);
11
      i2c_write(0x0a);        // schalte Ausgänge ein
12
      i2c_stop();  
13
      }
14
      else
15
      {
16
       i2c_start(MCP23017_ADDR);    // Adresse
17
       i2c_write(MCP23017_OLATA);
18
       i2c_write(0x00);        // schalte Ausgänge ein
19
       i2c_stop(); 
20
      }
vorher noch das:
1
//setzt Port A als Ausgang mit IODIRA              
2
  i2c_start(MCP23017_ADDR);      // Adresse
3
  i2c_write(MCP23017_IODIRA);      // Steuert die Richtung der Daten am Port A        
4
  i2c_write(0x00);          // Angabe Ausgang  0x00-alle, 0xff-alle aus
5
  i2c_stop();
6
  
7
  // setzt Port B alle R mit GPPUB als Eingang
8
  i2c_start(MCP23017_ADDR);    // Adresse
9
  i2c_write(MCP23017_GPPUB);    // aktivierung der internen Pullups Widerstände
10
  i2c_write(0xff);        // schalte alle Eingänge auf 5V
11
  i2c_stop();
Das schalten der LED am anderen Port geht ohne Probleme. Leider lassen 
sich die Taster nicht auslesen bzw. erfolgt keine Anzeige dazu.
Das mit den registern scheint doch nicht so einfach zu sein. Hat jemand 
eine Idee dazu?

LG Gast
Gast #5367540
Lesenswert?

Habe einen Schaltplan dazu. Dieser ist so einfach das ich nicht geladen 
habe.

- auf Port A von GPA 0 bis 7 habe ich 8 LEDs mit Vorwiderstand
- auf Port B von GPB 0 bis 7 habe ich 8 Taster nach Masse (GND)

zuzüglich der Adressen auf GND, ein paar C zur Abblockung und das wars 
schon
Gast #5368643
Lesenswert?

Hallo,

die gibt es schon aber, es ist immer eine Frage des Respekts 
untereinander.

Wenn So eine Frage "Habe einen Schaltplan dazu. Dieser ist so einfach 
das ich nicht geladen habe." aus Deiner Sicht unsinnig erscheint und 
keine Antwort erfolgt, dann mag auch kein Anderer(e) mehr auf Dich 
eingehen.

Ich würde immer ein komplettes (Test-)Programm und alle weiteren Infos 
zum Projekt posten, bevor ich fragen würde. So kann sich jeder auf den 
gleichen Stand bringen, auf dem man selbst ist.

Generell finde ich das Datenblatt nicht sehr schwer zu lesen mit - d.h. 
alle möglichen Fragen, können damit geklärt werden.

Ich würde mein Programm noch viel weiter modularisieren und z.B. 
Funktionaleeinheiten schaffeln, Register lesen und schreiben.
Dadurch entsteht eine neuen "Sprache" die den Zugriff auf den MCP23017 
vereinfachen.
Gast #5368677
Lesenswert?

Hallo Karl
Danke für deine Worte. Den Schaltplan besteht im Moment auf einem Blatt 
Papier und einem Steckbrett. Als Vorlage habe dazu das Datenblatt 
verwendet. Der Code steht weiter oben. Viel mehr habe ich im Moment 
kaum. Das einzigste was nicht drin steht ist die Zuordnung der Register.
1
#include <stdbool.h>
2
#include <avr/pgmspace.h>
3
#include "main.h"
4
#include "i2cmaster.h"
5
#include "avr/io.h"
6
#include "util/delay.h"
7
#include "avr/interrupt.h"
8
#include "stdlib.h"
9

10
// Controll Register ICON.Bank = 0
11
// Richtungsregister von Port A und B
12
#define MCP23017_IODIRA   0x00      // Steuert die Richtung der Daten am Port A, Pin gesetzt=Eingang, nicht gesetzt=Ausgang
13
#define MCP23017_IODIRB   0x01      // Steuert die Richtung der Daten am Port B, Pin gesetzt=Eingang, nicht gesetzt=Ausgang
14
// Register um Logik Polarität umzustellen an Port A und B
15
#define MCP23017_IPOLA   0x02      // konfiguriert die Polarität GPIO Port Bits
16
#define MCP23017_IPOLB   0x03
17

18
#define MCP23017_GPINTENA 0x04      // steuert die Interrupt-On-Change
19
#define MCP23017_GPINTENB 0x05
20

21
#define MCP23017_DEFVALA  0x06      // Standardvorgabe für Eingangspins 
22
#define MCP23017_DEFVALB  0x07
23
#define MCP23017_INTCONA  0x08      // legt fest wie der zugehörige Pin-Wert für die Interrupt-On-Change-Funktion verglichen wird
24
#define MCP23017_INTCONB  0x09
25

26
#define MCP23017_IOCON    0x0A      // enthält etliche Bits für die Konfiguration
27

28
// Interne Pull-Up-Widerstände einschalten an Port A und B
29
#define MCP23017_GPPUA    0x0C      // steuert die Pull-UP-Widerstände für Port-Pins
30
#define MCP23017_GPPUB    0x0D
31

32
#define MCP23017_INTFA    0x0E      // spiegelt die Interupt-Bedingungen auf den Port-Pins wieder
33
#define MCP23017_INTFB    0x0F
34

35
#define MCP23017_INTCAPA  0x10      // erfassen den GPIO-Port-Wert zum Zeitpunkt des Interrups 
36
#define MCP23017_INTCAPB  0x11
37
// Datenregister Port A und B
38
#define MCP23017_GPIOA    0x12      // geben den Wert der Portleitungen zurück. Ein lesen entspricht dem lesen der Portleitungen
39
#define MCP23017_GPIOB    0x13      // ein schreiben entspricht dem schreiben in die Ausgangslatches
40

41
#define MCP23017_OLATA    0x14      // erlaubt den Zugriff auf die als Ausgang konfigurierten Pins Register A
42
#define MCP23017_OLATB    0x15      // erlaubt den Zugriff auf die als Ausgang konfigurierten Pins Register B
43

44
#define MCP23017_ADDR  0x40        // Habe A0 bis A2 auf GND gelegt, Adresse 0x40
45
//#define Data
46
uint8_t Data;
47
int main(void)
48
  {   
49
  i2c_init();              // initialize I2C library
50
  
51
  //setzt Port A als Ausgang mit IODIRA              
52
  i2c_start(MCP23017_ADDR);      // Adresse
53
  i2c_write(MCP23017_IODIRA);      // Steuert die Richtung der Daten am Port A        
54
  i2c_write(0x00);          // Angabe Ausgang  0x00-alle, 0xff-alle aus
55
  i2c_stop();
56
  
57
  // setzt Port B alle R mit GPPUB als Eingang
58
  i2c_start(MCP23017_ADDR);    // Adresse
59
  i2c_write(MCP23017_GPPUB);    // aktivierung der internen Pullups Widerstände
60
  i2c_write(0xff);        // schalte alle Eingänge auf 5V
61
  i2c_stop();
62
  
63
  while(1)
64
    {
65
      // einlesen der Port / Taster
66
      i2c_start(MCP23017_ADDR);    // Adresse
67
      i2c_write(MCP23017_GPIOB);
68
      Data = i2c_read(0xff);        // liest Ausgänge ein
69
      i2c_stop();
70
    
71
    if (Data == 0x01)
72
      {
73
      i2c_start(MCP23017_ADDR);    // Adresse
74
      i2c_write(MCP23017_OLATA);
75
      i2c_write(0x0a);        // schalte Ausgänge ein
76
      i2c_stop();  
77
      }
78
      else
79
      {
80
       i2c_start(MCP23017_ADDR);    // Adresse
81
       i2c_write(MCP23017_OLATA);
82
       i2c_write(0x00);        // schalte Ausgänge ein
83
       i2c_stop(); 
84
      }
85
   
86
      
87
    // schreiben der Rister für LEDs  
88
    i2c_start(MCP23017_ADDR);    // Adresse
89
    i2c_write(MCP23017_OLATA);                                  
90
    i2c_write(0x05);        // schalte Ausgänge ein
91
    i2c_stop();
92
    
93
    _delay_ms(1500);
94
    
95
    i2c_start(MCP23017_ADDR);    // Adresse
96
    i2c_write(MCP23017_OLATA);                                  
97
    i2c_write(0x50);        // schalte Ausgänge aus
98
    i2c_stop();
99
    
100
    _delay_ms(1500);
101
      }
102
  }
Soweit möglich habe ich in den Kommentaren alle Zuordnungen und Namen 
reingeschrieben.
Das schalten der LEDs erfolgt ohne Probleme. Leider die Abfrage der 
Taster nicht.
Damit bist du auf dem selben Stand wie ich.
#5368829
Lesenswert?

Was passiert denn wenn man das gelesene byte der Eingänge direkt auf das 
latchregister des anderen Ports schreibt mit unter 100ms delay als Loop?

Theoretisch sollte dann ja für jeden taster 1 Led zugeordnet sein.

So lässt sich besser der Fehler suchen und die Grundfunktion überprüfen.

EDIT Beispiel:
1
while(1)
2
    {
3
      // einlesen der Port / Taster
4
      i2c_start(MCP23017_ADDR);    // Adresse
5
      i2c_write(MCP23017_GPIOB);
6
      Data = i2c_read(0xff);        // liest Ausgänge ein
7
      i2c_stop();
8
    
9
      i2c_start(MCP23017_ADDR);    // Adresse
10
      i2c_write(MCP23017_OLATA);
11
      i2c_write(Data);        // schalte Ausgänge ein
12
      i2c_stop();  
13
     _delay_ms(100);
14
  }
(Firma: Flk Consulting UG) #5368872
Lesenswert?

Hallo,

Hier fehlt zumindest eine Zeile Code
1
i2c_start(MCP23017_ADDR);    // Adresse
2
i2c_write(MCP23017_GPIOB);
3
i2c_start(MCP23017_ADDR + 1);
4
Data = i2c_read(0xff);

Der MCP muss explizit in den Readmodus gesetzt werden.

Ansonsten wäre noch interessant welche I2C Lib Du verwendest.

Gruß
Frank
#5369294
Lesenswert?

Wolfgang R. schrieb:
> Ich habe zwar deinen Code nicht wirklich analysiert sondern nur kurz
> überflogen, aber fehlt nicht irgendwo ein IODIRB auf 0xFF?

Ich muss mich korrigieren: Auch wenn ich es explizit so setze ist es 
nicht erforderlich, da IODIRA und IODIRB als default 0xFF gesetzt sind.

Aber: Ich denke, du musst IOPOLB auf 0xFF setzen damit deine Abfrage auf 
(Data == 0x01) wie gewünscht reagiert.
Gast #5370110
Lesenswert?

Hallo an alle
Erst einmal danke für eure Hilfe. Bin gerade dabei es zu lesen und in 
den Code zu schreiben. Zu euren Fragen.

Frank L. schrieb:
> Ansonsten wäre noch interessant welche I2C Lib Du verwendest.

Ich verwende den Code von Peter. Der hat bisher alles mitgemacht.

Philipp K. schrieb:
> // einlesen der Port / Taster
>       i2c_start(MCP23017_ADDR);    // Adresse
>       i2c_write(MCP23017_GPIOB);
>       Data = i2c_read(0xff);        // liest Ausgänge ein
>       i2c_stop();
>
>       i2c_start(MCP23017_ADDR);    // Adresse
>       i2c_write(MCP23017_OLATA);
>       i2c_write(Data);        // schalte Ausgänge ein
>       i2c_stop();
>      _delay_ms(100);

Habe das eingefügt und die änderung dazu mit der Adresse.
Hat leider kein Funktion.

Wolfgang R. schrieb:
> Aber: Ich denke, du musst IOPOLB auf 0xFF setzen damit deine Abfrage auf
> (Data == 0x01) wie gewünscht reagiert.

Sorry, muss das nicht IPOLB sein? Auf welche Zeile im Code beziehst du 
das?
Gast #5370266
Lesenswert?

Den gesamten Code habe ich bereits oben eingestellt. Habe nur die 
änderungen dazu geschrieben und das blinken der LED auskommentiert.
das sieht jetzt so aus:
1
#include <stdbool.h>
2
#include <avr/pgmspace.h>
3
#include "main.h"
4
#include "i2cmaster.h"
5
#include "avr/io.h"
6
#include "util/delay.h"
7
#include "avr/interrupt.h"
8
#include "stdlib.h"
9

10
// Controll Register ICON.Bank = 0
11
// Richtungsregister von Port A und B
12
#define MCP23017_IODIRA   0x00      // Steuert die Richtung der Daten am Port A, Pin gesetzt=Eingang, nicht gesetzt=Ausgang
13
#define MCP23017_IODIRB   0x01      // Steuert die Richtung der Daten am Port B, Pin gesetzt=Eingang, nicht gesetzt=Ausgang
14
// Register um Logik Polarität umzustellen an Port A und B
15
#define MCP23017_IPOLA   0x02      // konfiguriert die Polarität GPIO Port Bits
16
#define MCP23017_IPOLB   0x03
17

18
#define MCP23017_GPINTENA 0x04      // steuert die Interrupt-On-Change
19
#define MCP23017_GPINTENB 0x05
20

21
#define MCP23017_DEFVALA  0x06      // Standardvorgabe für Eingangspins 
22
#define MCP23017_DEFVALB  0x07
23
#define MCP23017_INTCONA  0x08      // legt fest wie der zugehörige Pin-Wert für die Interrupt-On-Change-Funktion verglichen wird
24
#define MCP23017_INTCONB  0x09
25

26
#define MCP23017_IOCON    0x0A      // enthält etliche Bits für die Konfiguration
27

28
// Interne Pull-Up-Widerstände einschalten an Port A und B
29
#define MCP23017_GPPUA    0x0C      // steuert die Pull-UP-Widerstände für Port-Pins
30
#define MCP23017_GPPUB    0x0D
31

32
#define MCP23017_INTFA    0x0E      // spiegelt die Interupt-Bedingungen auf den Port-Pins wieder
33
#define MCP23017_INTFB    0x0F
34

35
#define MCP23017_INTCAPA  0x10      // erfassen den GPIO-Port-Wert zum Zeitpunkt des Interrups 
36
#define MCP23017_INTCAPB  0x11
37
// Datenregister Port A und B
38
#define MCP23017_GPIOA    0x12      // geben den Wert der Portleitungen zurück. Ein lesen entspricht dem lesen der Portleitungen
39
#define MCP23017_GPIOB    0x13      // ein schreiben entspricht dem schreiben in die Ausgangslatches
40

41
#define MCP23017_OLATA    0x14      // erlaubt den Zugriff auf die als Ausgang konfigurierten Pins Register A
42
#define MCP23017_OLATB    0x15      // erlaubt den Zugriff auf die als Ausgang konfigurierten Pins Register B
43

44
#define MCP23017_ADDR  0x40        // Habe A0 bis A2 auf GND gelegt, Adresse 0x40
45

46
//#define Data
47
uint8_t Data;
48
int main(void)
49
  {   
50
  i2c_init();              // initialize I2C library
51
  
52
  //setzt Port A als Ausgang mit IODIRA              
53
  i2c_start(MCP23017_ADDR);      // Adresse
54
  i2c_write(MCP23017_IODIRA);      // Steuert die Richtung der Daten am Port A        
55
  i2c_write(0x00);          // Angabe Ausgang  0x00-alle, 0xff-alle aus
56
  i2c_stop();
57
  
58
  // setzt Port B alle R mit GPPUB als Eingang
59
  i2c_start(MCP23017_ADDR);    // Adresse
60
  i2c_write(MCP23017_GPPUB);    // aktivierung der internen Pullups Widerstände
61
  i2c_write(0xff);        // schalte alle Eingänge auf 5V
62
  i2c_stop();
63

64
  while(1)
65
    {
66
      
67
    // einlesen der Port / Taster
68
    i2c_start(MCP23017_ADDR +1);    // Adresse
69
    i2c_write(MCP23017_GPIOB);
70
    i2c_read(0x00);
71
    Data = i2c_read(0x01);        // liest Ausgänge ein
72
    i2c_stop();
73
    
74
    if (!(Data & 0x01))
75
    {
76
      i2c_start(MCP23017_ADDR);    // Adresse
77
      i2c_write(MCP23017_OLATA);
78
      i2c_write(0x10);        // schalte Ausgänge ein  Grün
79
      i2c_stop();
80
    }
81
    else
82
    {
83
      i2c_start(MCP23017_ADDR);    // Adresse
84
      i2c_write(MCP23017_OLATA);
85
      i2c_write(0x02);        // schalte Ausgänge ein  Rot
86
      i2c_stop();
87
      _delay_ms(1500);
88
    }  
89
      }
90
  }
Ein Foto gibt es nicht. Die Hardware befindet sich auf einem Steckbrett 
und ist die Schöheit.
Aufbau ist ein kompletter Port als Taster Eingang und der andere Port 
vollständig mit LED.
Die ansteurung der LED geht ohne Probleme. Ist wahrscheinlich auch der 
leichte Teil des Problems
Gast #5370291
Lesenswert?

Hallo,

dieser Code ist grundsätzlich falsch!
1
i2c_start(MCP23017_ADDR +1);    // Adresse
2
i2c_write(MCP23017_GPIOB);
3
i2c_read(0x00);
4
Data = i2c_read(0x01);        // liest Ausgänge ein
5
i2c_stop();

Mit i2c_start(MCP23017_ADDR +1); signalisiert man über I2C einen 
Lesevorgang, aber dann erfolgt eine Schreibzugriff!
1
uint8_t Data = 0;
2
if (i2c_start(MCP23017_ADDR)) { // Write-Adresse, mit Fehlerüberprüfung, falls das die Lib so macht!
3
i2c_write(MCP23017_GPIOB);
4
i2c_stop();
5

6
 if (i2c_start(MCP23017_ADDR +1)) { // Read-Adresse, mit Fehlerüberprüfung, falls das die Lib so macht!
7
  Data = i2c_read();        // liest Ausgänge ein
8
  i2c_stop();
9
 } else { // error!
10
 }
11
} else { // error!
12
}
Gast #5370296
Lesenswert?

Hallo,

i2c_readNak() vergessen.
1
uint8_t Data = 0;
2
if (i2c_start(MCP23017_ADDR)) { // Write-Adresse, mit Fehlerüberprüfung, falls das die Lib so macht!
3
i2c_write(MCP23017_GPIOB);
4
i2c_stop();
5

6
 if (i2c_start(MCP23017_ADDR +1)) { // Read-Adresse, mit Fehlerüberprüfung, falls das die Lib so macht!
7
  Data = i2c_readNak();        // liest Ausgänge ein
8
  i2c_stop();
9
 } else { // error!
10
 }
11
} else { // error!
12
}

http://homepage.hispeed.ch/peterfleury/doxygen/avr-gcc-libraries/group__pfleury__ic2master.html
Gast #5370302
Lesenswert?

Nachtrag 2,

Aus der Beschreibung.
1
unsigned char i2c_start(unsigned char addr)
Issues a start condition and sends address and transfer direction.

Parameters
addr  address and transfer direction of I2C device
Return values
0  device accessible
1  failed to access device

Man muss also noch etwas ändern:
1
uint8_t Data = 0;
2
if (i2c_start(MCP23017_ADDR) == 0) { // Write-Adresse, mit Fehlerüberprüfung, falls das die Lib so macht!
3
i2c_write(MCP23017_GPIOB);
4

5
 if (i2c_rep_start(MCP23017_ADDR +1) == 0) { // Read-Adresse, mit Fehlerüberprüfung, falls das die Lib so macht!
6
  Data = i2c_readNak();        // liest Ausgänge ein
7
  i2c_stop();
8
 } else { // error!
9
 }
10
} else { // error!
11
}
#5370324
Lesenswert?

> Wolfgang R. schrieb:
>> Aber: Ich denke, du musst IOPOLB auf 0xFF setzen damit deine Abfrage auf
>> (Data == 0x01) wie gewünscht reagiert.
>
> Sorry, muss das nicht IPOLB sein? Auf welche Zeile im Code beziehst du
> das?

Ja richtig - heißt tatsächlich IPOLB

Ich meine, das muss in die Initialisierung des MCP23017. So würde das 
passen:
1
... ...
2
int main(void)
3
  {   
4
  i2c_init();              // initialize I2C library
5
  
6
  //setzt Port A als Ausgang mit IODIRA              
7
  i2c_start(MCP23017_ADDR);      // Adresse
8
  i2c_write(MCP23017_IODIRA);      // Steuert die Richtung der Daten am Port A        
9
  i2c_write(0x00);          // Angabe Ausgang  0x00-alle, 0xff-alle aus
10
  i2c_stop();
11
  
12
  // Alle Eingänge Port B invertieren
13
  i2c_start(MCP23017_ADDR);    // Adresse
14
  i2c_write(MCP23017_IPOLB);    // Taster schalten Masse (active-low)
15
  i2c_write(0xff);        // alle Eingänge invertieren
16
  i2c_stop();
17

18
  // setzt Port B alle R mit GPPUB als Eingang
19
  i2c_start(MCP23017_ADDR);    // Adresse
20
  i2c_write(MCP23017_GPPUB);    // aktivierung der internen Pullups Widerstände
21
  i2c_write(0xff);        // schalte alle Eingänge auf 5V
22
  i2c_stop();
23

24
  while(1)
25
  ... ...
Gast #5370372
Lesenswert?

Hallo Karl
habe deinen Code eingetragen. Es sieht jetzt so aus:
1
i2c_start(MCP23017_ADDR);    // Adresse
2
    i2c_write(MCP23017_GPIOB);
3
    i2c_stop();
4
    
5
    i2c_start(MCP23017_ADDR +1);    // Read-Adresse, mit Fehlerüberprüfung, falls das die Lib so macht!
6
    Data = i2c_readNak();      // liest Ausgänge ein
7
    i2c_stop();
8
    
9
    if (!(Data & 0x04))    //0x01
10
      {
11
      i2c_start(MCP23017_ADDR);    // Adresse
12
      i2c_write(MCP23017_OLATA);
13
      i2c_write(0x10);        // schalte Ausgänge ein  Grün
14
      i2c_stop();
15
      }
16
    else
17
      {
18
      i2c_start(MCP23017_ADDR);    // Adresse
19
      i2c_write(MCP23017_OLATA);
20
      i2c_write(0x02);        // schalte Ausgänge ein  Rot
21
      i2c_stop();
22
      }
Damit erfolgt jetzt die Umschaltung zwischen den beiden LEDs wenn ich 
einen Taster betätige. Die Auswahl der Taster erfolgt durch Data.
Danke für deine Hilfe
Gast #5370902
Lesenswert?

Hallo
möchte noch mal drauf hinweisen, das mit den oberen Beispielen das 
schalten von LEDs und die Benutzung von Tastern geht.
Kann jeder verwenden. Kommen wir aber zum nächsten Problem.
Vielen Dank für eure Hilfe

LG F.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren