Forum: Compiler & IDEs PCF8574 über I2C


von Stefan T. (stefan90)


Angehängte Dateien:

Lesenswert?

Hallo zusammen.

Ich möchte einen PCF8574 mit einem Mega8 über I2C zum Laufen bringen.
Die Adressierung funtioniert schon mal. Und die Start Condition läuft
bereits.

Nur wie kann ich nun Daten senden? Also es soll nun z.B eine LED an P0
des I2C-Slave zum Leuchten gebracht werden. Nur wie stelle ich das an?
Muss ich erneut eine Adresse schicken?

Also am lcd-Display hab ich derzeit 000, also der avr bleibt nirgendwo
hängen

Für Antworten wäre ich sehr dankbar

Gruß Stefan

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?


von Stefan T. (stefan90)


Lesenswert?

Hallo Anderas

Danke erstmal für den Link, jetzt weiß ich endlich mehr!

Nur eins ist mir noch nicht klar.
Ich will nun wenn Schalter an P7 gedrückt ist, dass die Led an P0
leuchtet.

Das Abfragen ist ja kein Problem aber wie sende ich dann, also damit
nur der P0-Pin auf high gesetzt wird, alle anderen aber gleich
bleiben?

Gruß Stefan

von Robert Schilling (Gast)


Lesenswert?

Hallo Stefan

Wenn du ausgelesen hast, weißt du erstmal den Status aller Output Pins

[/C]
if(bit_is_set(readout, 7))
    readout |= (1 << 0);
else
    readout &= ~(1 << 0);

pcf8574_send(readout);
[/C]

GRuß Robert

von Stefan T. (stefan90)


Lesenswert?

Danke Robert, der Code funktioniert erst mal.

Nur eins ist mir nicht klar.

Hier nun erstmal der Code:

#include <stdlib.h>
#include <avr/io.h>
#include "lcd.h"

#define ADRESS 0x20

void i2c_start(uint8_t rw)
{
  unsigned char addr_byte=0;

  TWBR = (1 << 1) | (1 << 3);  //I2C initialisieren, TWBR=10 -> SCL
freq=83.33 kHz

  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);  //Sende Start Condition
  while(!(TWCR & (1<<TWINT)));          //Warte bis Übertragung beendet 
ist

  addr_byte = ADRESS << 1;  //addr_byte=adress und um 1 bit nach links
verschieben (für r/w bit)
  addr_byte |= rw;      //r/w bit hinzufügen
  addr_byte |= 0b01000000;  //Aresscode vom PCF8574 (1. 4 Stellen = 0100
siehe Datenblatt)
  TWDR = addr_byte;      //Adresse senden
  TWCR = (1 << TWINT) | (1 << TWEN);  //Clear TWINT bit in TWCR to start
transmission of address

  while(!(TWCR & (1 << TWINT)));  //Warte bis Übertragung beendet ist
}

void i2c_send(unsigned char data)
{
  TWDR= data;              //Daten senden
  TWCR = (1 << TWINT) | (1 << TWEN);  //Clear TWINT bit in TWCR to start
transmission of data

  while(!(TWCR & (1 << TWINT)));  //Warte bis Übertragung beendet ist
}

unsigned char i2c_read (void)
{
  /*send content of TWDR; TWEA = enable ACK*/
  TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
  /*wait, until byte has been received --> ACK*/
  while (!(TWCR & (1<<TWINT)));
  return TWDR;
}


void i2c_stop(void)
{
  TWCR= (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);  //Sende Stop-Condition
  while(!(TWCR & (1 << TWSTO)));        //Warte bis Übertragung beendet 
ist
}

void wait(void)
{
  for (int i=0; i<20000; i++)      //delay
    for (int j=0; j<10; j++) asm volatile ("nop");
}

int main (void)
{
  char input;
  PORTC |= _BV(PC4);  //Enable Pullup
  PORTC |= _BV(PC5);  //Enable Pullup

  i2c_start(0);    //I2C initialisieren und Start senden + MT Modus
  i2c_send(0xFF);    //Daten senden, alle Pins auf high

  i2c_stop();      //Stop senden
  i2c_start(1);    //I2C initialisieren und Start senden + MR Modus

  lcd_init(LCD_DISP_ON);  //lcd initialisieren
  lcd_clrscr();
  lcd_gotoxy(8,0);
  lcd_puts("I2C - TEST");
  lcd_gotoxy(0,2);
  lcd_puts("Zum Start Schalter an\nP7 des PCF8574 betaetigen");

  wait();  wait();    //Warte

  lcd_clrscr();

  for(;;)
  {
    input=i2c_read();      //Status der Pins in input speichern

    for(int i=4;i<8;i++)    //Status der Pins auf lcd ausgeben
    {
      if (input & (1<<i))  //bei P4 beginnen (aslo Binärcode genau 
verkehrt
herum anzeigen)
      {            //entspricht dann genau Schalteranordnung
        lcd_puts("1");
      }
      else
      {
        lcd_puts("0");
      }
    }

    if(bit_is_clear(input,7))  //Wenn 7. Bit in input gelöscht ist ->
Schalter betätigt
    {
      input &=~ (1<<0);     //P0 auf 0 setzen -> LED ein
      input |= (1<<7);    //Schalter PIN weiter auf high setzten, sonst
(Pin=0) Abfrage
    }              //nicht mehr möglich
    else
    {
      input |= (1<<0);     //P0 auf 1 setzen -> LED aus
      input |= (1<<7);    //Schalter PIN weiter auf high setzten, sonst 
(Pin
= 0) Abfrage
    }              //nicht mehr möglich

    //hier darf kein stop(); rein sonst funktionierts nicht, wenn doch
stop(); dann gehört
    //folgendes dazugeschrieben:

    // i2c_stop();  TWCR=0; oder TWCR=1;

    i2c_start(0);    //In MT-Modus wechseln
    i2c_send(input);   //input senden
    i2c_stop(); i2c_start(1);  //In MR-Modus wechseln

    wait();
    lcd_clrscr();
  }

  return 0;
}


Nun:
1.) Warum darf ich das stop() nicht reinschreiben? bzw. warum gehört
dann TWCR=0 oder =1 dazu?

2.) Warum muss der Schalterpin immer auf 1 sein? also: input |= (1<<7);
hängt das damit zusammen, dass die Schalter auf GND gehen und der
Schalter bewirkt dass dann das bit gelöscht wird, nicht aber das
Schalten auf VCC bzw. GND?

3.) In meiner i2c_start() lege ich fest dass TWBR gleich 10 ist ->
Frequenz = 83.33kHz. Sollte die aber nicht 100kHz betragen? Man soll
aber laut Atmel nicht unter 10 in TWBR gehen. Wie soll das gehen?

Ich hoffe da kann mir jemand weiterhelfen

Gruß Stefan

von Stefan T. (stefan90)


Angehängte Dateien:

Lesenswert?

hier der code als Anhang, dann ist es übersichtlicher

von Eugen K. (kannsnet)


Lesenswert?

Hallo,
was für einen Wert nimmst du für TWPS an wenn du SCL berechnest?
Beziehungsweise kann man den Inhalt von TWPS in der Software 
beeinflussen?

SCL = CPU CLOCK / (16 + 2(TWBR)*4^TWPS)

Gruß Eugen

von Eugen K. (kannsnet)


Lesenswert?

ok ich hab des jetzt gerechnet, und so wie es scheint hast du mit einem 
cpu clock von 8MHz gerechnet. dann kommt am ende raus 4,000=4^TWPS. und 
dann kann man annehmen das TWPS 1 ist bei dir.

von Gast (Gast)


Lesenswert?

>ok ich hab des jetzt gerechnet,

Auch ich habe gerechnet: zwei Jahre, zwei Monate und sieben Tage ist die 
Anfrage alt.

von Peter Diener (Gast)


Lesenswert?

Hallo nochmal,

wenn ich so nachdenke, kann es ja eigentlich nur die Station zweiter 
Generation sein, die du benutzt. Hat die nicht genug Ports, um ein LCD 
im 4 bit-Modus direkt anzusteuern? Das wäre erheblich einfacher. Das was 
vorher auf den Ports war, muss für ein Aquarium bestimmt nicht schnell 
sein und kann daher bequem über den PCF erledigt werden.

Oder ist da ein Denkfehler drin?

Peter

von Peter Diener (Gast)


Lesenswert?

Was ist denn jetzt los, mein Beitrag gehört woanders hin. Bitte löschen.

Danke,

Peter

von roboter (Gast)


Lesenswert?

Hört sich interessant an.
Kann man damit zb auch ein i2cEEpron 24c256 betreiben oder ein 
Kompassmodul Cmps03?

mfg

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.