Hi an alle. Ich konnte nun nach etwas Arbeit meinen MCP23016 Port Expander und meinen atmega168 miteinander sprechen lassen. Ich habe an dem atmega168 einen Button gehängt und die LEDs an den MCP23016 gesteckt. Nach drücken des Buttons leuchten die LEDs. Projekt gelungen. Nun möchte ich aber den verkehrten Weg probieren. Und zwar dass die LEDs am atmega168 hängen und der Button am MCP23016. Leider komme ich nicht dahinter wie ich dort einen Imput(in diesem Fall einen Button) richtig anspreche. Das definieren der Input Ports habe ich schon gemacht. Kann mir jemand dabei helfen? Zur Erklärung: Die Leds sind im Moment an GP0.0-GP0.7 gehängt. Der Button hängt an PB1. Meinen bestehenden Code mit der Realisierung des Outputs habe ich in diesem Thread angehängt. Hier der Datasheet des MCP23016: http://ww1.microchip.com/downloads/en/DeviceDoc/20090C.pdf
Das ist ein i2C Port Expander und den kann man wie jedes andere I2C- gerät ansteuern und konfigurieren. Aber das ist glaube Ich nicht richtig i2c_write(0x06); // Auswahl IODIR (pointer) i2c_write(0x00); // DDR Port0 all output i2c_write(0xFF); // DDR Port1 all input 0xFF = B11111111 Das sind die register in die du was schreiben willst, aber was du schreiben willst, steht nicht drin. Das muss ungefähr so aussehen: i2c_write(0x00,0xFF); // DDR Port0 all output Wie das genau geht muss in dem manual für deinen compiler stehen.
Hi, ich denke schon, dass es so stimmt, da das Programm schließlich auch so funktioniert. Außerdem habe ich die Bibliothek von Peter Fleury verwendet, in welcher man soweit ich gesehen habe bei den verwendeten Funktionen nur einen Parameter übergibt. Den Teil den zu kommentiert hast ist lediglich die Initialierung des I2C. Das Ansprechen der LEDs erfolgt in der Main Funktion und funktioniert ohne Probleme wenn ich die LEDs als Ausgang verwende. Nur möchte ich eben am Port Expander einen Eigang setzen. Z.b.: einen Button.
El Nino schrieb: > Nur möchte ich eben am Port Expander einen Eigang setzen. Z.b.: einen > > Button. Wo soll er sein? An welchem pin? Wenn du in das Datenblatt von der Mcp23016 schaust dann wirst du sehen, dass das hier (0x06) die addresse von dem IODIR register ist.Und dieser register ist dafür zuständig ob die ports eingang oder ausgang sein sollen.Also wenn du da eine 1 schreibst dann sind die entsprechenden pins input und andersrum eben output. Dieser register ist aber nur für den Port0 zuständig.Für den Port1 ist ein anderer register zuständig. i2c_write(0x06); // Auswahl IODIR (pointer)
Für den Port1 ist der IODIR1 register zuständig.Und seine Addresse ist 0x07 Also wenn alle Pins an dem Port1 input sein sollen dann würde Ich das so machen. i2c_write(0x07); // Auswahl IODIR1 (pointer) i2c_write(0xFF); // DDR Port1 all input 0xFF = B11111111
Das ist aber nicht nötig, weil sie automatisch auf input stehen.
Hi Programist, danke für deine Antworten. Das heisst zu Beginn sind die Ports von GP0 und GP1 als Input gesetzt. Mit meinem jetzigen Code habe ich also GP0 als Output und GP1 als Input gesetzt. Ist das so korrekt? Wenn ich nun an GP1.0 einen Button anschließe, wie soll dies dann aussehen? Den "normalen Weg" mit ..
1 | if(!(PINB & (1<<PB1))) // When Button is pressed |
2 | { |
3 | // do something |
4 | } |
..kann ich ja nicht machen weil es dieses Register auf dem Expander gar nicht gibt. Wie kann ich dann abfragen ob ein Button an GP1.0 gedrückt worden ist? Gibt es da dann vielleicht eine i2c_read Funktion? Vielleicht kann mir da jemand weiter helfen?
El Nino schrieb: > Das heisst zu Beginn sind die Ports von GP0 und GP1 als Input gesetzt. > > Mit meinem jetzigen Code habe ich also GP0 als Output und GP1 als Input > > gesetzt. > > > > Ist das so korrekt? Ja das stimmt. El Nino schrieb: > Wie kann ich dann abfragen ob ein Button an GP1.0 gedrückt worden ist? Dazu musst du zuerst den register GP1 lessen und dann den kopieren auf ein anderes register auf den dein programm zugreifen kann.
Danke für deine rückmeldung. kannst du mir diesen fall ein anwendungsbeispiel nennen? welches register des atmega168 kann Ich dafür verwenden? und wie lese Ich den wert des gp1.0 aus? es funktioniert also ganz anders als beim ausgang? danke für deine hilfe.
Ich kann dir ein anwendungsbeispiel nennen, aber nicht für deinen compiler. Das funktioniert unterschiedlich bei anderen compilern.Aber du must sowieso zuest im allgemeinen programieren lernen, weil du viel zu wenig Ahnung davon hast.
Ich hoffe es ist okay meinen alten Thread wieder aufzuwärmen. Bin nun wieder dazu gekommen mich dem Thema zu widmen und habe mich etwas vertrauter mit dem MCP23016 gemacht. Die Ausgabe habe ich nun vollends vollstanden und den Code dementsprechend angepasst. Ich kann nun jeden Port auf High oder Low setzen und Input oder Output. Die Realisierung des Inputs ist mir jedoch immer noch nicht klar. Wenn ich annehme an GP1.1 hängt ein Taster und ich möchte im Code abfragen ob dieser gedrückt wurde. Normal mache ich das ja mit: if(!(PINB & (1<<PB1))) Wie realisiere ich das wenn der Taster nicht am ATMega168 hängt sondern am GP1.1 vom MCP23106. Hat das jemand von euch schon umgesetzt?
Hallo Nino Ich weiss nicht obs für dich aktuell ist, aber ich habe das selbe Problem, oder ähnlich :-) Bei meiner Hardware habe ich 3 Buttons, die ich mit pollen nach dem Zustand abfrage.
1 | Display_Read(0x0, &Data); |
2 | if(Data == 0x08) |
3 | {
|
4 | Switch_On(LED_Blink2); |
5 | }
|
Bei mir sieht das Read dann so aus (Beispiel Demo.c von Keil)
1 | bool Display_Read (uint8_t reg, uint8_t *val) |
2 | {
|
3 | uint8_t data[1]; |
4 | int32_t n; |
5 | |
6 | data[0] = reg; |
7 | n = ptrI2C->SendData(DISPLAY_I2C_ADDR, data, 1, true); |
8 | if (n != 1) return false; |
9 | |
10 | n = ptrI2C->ReceiveData(DISPLAY_I2C_ADDR, val, 1, false); |
11 | if (n != 1) return false; |
12 | |
13 | return true; |
14 | }
|
Dies läuft bei mir ohne Probleme, ich kann auch einen Buzzer an einem einzelnen Ausgang setzen. Am anderen Port GP1, habe ich jetzt ein Display im 4 Bit Mode, dass ich ansteuern möchte und weil dies nicht funktioniert, frage ich mich, ob mein Vorgehen richtig ist. Display Treiber HD44780U. GP1 outputs:
1 | Dispaly_Write(0x07); |
2 | Dispaly_Write(0x00); |
Dann setze ich die Outputs:
1 | Dispaly_Write(0x01); // hier wähle ich GP1 |
2 | Dispaly_Write(0x42); // hier sende ich; 4 um den E zu setzen und 2 high nibble |
3 | Dispaly_Write(0x48); // 4 = E, 8 = low nibble |
4 | Dispaly_Write(0x00); // 0 = E rücksetzen um die Daten zu übernehmen |
Meine Frage nun, da dies so nicht funktioniert, müsste ich nun vor jedem Befehl, den GP1 anwählen? Habe dies versucht und hat nicht geklappt. Ich komme einfach nicht drauf, wie dies funktioniert. Vielleicht liegt der Fehler beim Display Treiber? Vielleicht hat jemand eine Idee? Grüsse M.B.
Nachtrag: Ich verwende den STM32F405IG und das yVision von Keil MDK 5
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.