PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PCF 8574 auslesen



atmegadennis
06.02.2009, 08:38
Hallo zuasmmen,

habe folgendes Problem:

Lese mit einem Mega16 einen PCF8574 aus.

dazu verwende ich folgende Standardroutinen:



void pcf8574_init (void)
{
/*set bus speed*/
TWBR = 0x40;
}


unsigned char pcf8574_send_start (void)
{
/*writing a one to TWINT clears it, TWSTA=Start, TWEN=TWI-enable*/
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
/*wait, until start condition has been sent --> ACK*/
while (!(TWCR & (1<<TWINT)));
return TWSR;
}


void pcf8574_send_stop (void)
{
/*writing a one to TWINT clears it, TWSTO=Stop, TWEN=TWI-enable*/
TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
}


unsigned char pcf8574_send_add_rw (unsigned char address, unsigned char rw)
{
/*address can be 0 .. 8; rw=0 --> write, rw=1 --> read*/
unsigned char addr_byte = 0;
/*shift address one bit left*/
addr_byte = address << 1;
/*set RW-Bit, if necessary*/
addr_byte |= rw;
/*0b0100xxx0 --> address of Expander*/
addr_byte |= 0b01000000;
/*TWDR contains byte to send*/
TWDR = addr_byte;
/*send content of TWDR*/
TWCR = (1<<TWINT) | (1<<TWEN);
/*wait, until address has been sent --> ACK*/
while (!(TWCR & (1<<TWINT)));
return TWSR;
}


unsigned char pcf8574_send_byte (unsigned char byte)
{
/*TWDR contains byte to send*/
TWDR = byte;
/*send content of TWDR*/
TWCR = (1<<TWINT) | (1<<TWEN);
/*wait, until byte has been sent --> ACK*/
while (!(TWCR & (1<<TWINT)));
return TWSR;
}


unsigned char pcf8574_read_byte (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;
}


unsigned char pcf8574_get_inputs (unsigned char address)
{
pcf8574_init ();
pcf8574_send_start ();
pcf8574_send_add_rw (address, 1);
unsigned char input = pcf8574_read_byte ();
pcf8574_send_stop ();
return input;
}


void pcf8574_set_outputs (unsigned char address, unsigned char byte)
{
pcf8574_init ();
pcf8574_send_start ();
pcf8574_send_add_rw (address, 0);
pcf8574_send_byte (byte);
pcf8574_send_stop ();
}

nimm bitte "code" und nicht "list" (PicNick, Mod.)

Das ganze funktioniert so lange, bis ich den 8. Eingang auf low ziehe, ich bekomme dann einmalig die information, aber danach hängt sich die ganze Kommunikation über den IIC Bus auf und ich muss den uC wieder neu starten.


Kann mir jemand erklären woran das liegt ??

Ich habe schon herausgefunden, das sich die ganze Sache an folgender Stelle im send_start aufhängt

while (!(TWCR & (1<<TWINT)));

Diese bedingung wird nicht erfüllt nur warum ??


Vielen DAnk schon einmal im vorraus

Andun
06.02.2009, 12:58
Moin

Uff.. .. also ich muss gestehen ich hab deinen Code nicht durchgearbeitet, da ich dazu grade keine Zeit habe, aber hier mal ein paar Standard-Tipps die mich bei I2C anfangs weitergebracht haben:

1. Ja, du brauchst wirklcih zu extra Widerstände als PullUp, die internen vom Atmega reichen nicht aus.
2. Anstand lange mit eigenem Code rum zu probieren hab ich lieber die fertige Lib genommen und dann zur Kapselung Funktionen außenrum geschrieben.
http://jump.to/fleury und da auf AVR-Software - Libs

Vll kann dir ja aber jemand anderes noch helfen, warum dein Code nicht geht.

mfg
Andun

atmegadennis
06.02.2009, 13:13
habe fehler soeben gefunden :-)

/*send content of TWDR; TWEA = enable ACK*/
TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);

ich habe den TWEA gelöscht, da laut Datenblatt bei einem Lesevorgang kein ACK mehr zurück kommt, aber dennoch DAnke.

P.S. Das ist ein fertiger Code, der nur ein wenig geändert wurde :-)