PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATmega16 als TWI-Slave



JeyBee
26.05.2010, 14:34
Moin alle,

Ich versuche mich hier schon seit längerer zeit an einem TWI Slave, basierend auf ienem ATmega16.
Das Datenblatt gibt ja Infos über die Adressregister, den TWI-Flag und weiteres, denoch habe ich bisher nur misserfolge zu verzeichnen.

Es geht darum, Daten von einem ATmega16 über TWI zu einem anderen ATmega16 zu senden. Die TWI_Mastersoftware auf dem einen mega16 läuft einwandfrei, so dass ich einen LM75 auslesen kann und einen M24C02 beschreiben kann etc.


Mein Code der im Anschluss gepostet ist hat nur zur folge, dass auf dem LCD des Slaves immer nur "10010000" zu sehen ist.



#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"

#define Dev24C02 0xA0 // EEprom twi Adresse
#define LM75 0x90 // Temperatursensor twi Adresse

void twi_slave_init(void)
{
TWAR = 0xCC;
TWCR |= (1<<TWEN) | (1<<TWEA);
}


int main(void)
{
uint8_t output;
unsigned char buffer[10];

lcd_init(LCD_DISP_ON); // LCD initialisieren
twi_slave_init(); // TWI Slave initialisieren



while(1)
{

if(TWCR = 0b10000000); //Wenn TWINT = 1, dann TWSR auslesen
{
output = TWSR;
}

lcd_clrscr();
lcd_gotoxy(0,0);
lcd_puts(itoa(output, buffer, 2));

_delay_ms(300);
}
}


Sehe ich das richtig, dass mein Fehler beim auslesen der TWINT Flag über die IF-Schleife ist?

Kann mir jemand sagen, wo der Fehler ist?


Gruss Jey

yaro
26.05.2010, 14:49
Wahrscheinlich meintest du:

if(TWCR & 0b10000000) //Wenn TWINT = 1, dann TWSR auslesen
{
output = TWSR;
}

Gruß, Yaro

yaro
26.05.2010, 14:54
Ich würde aber folgendes bevorzugen:


while(1)
{

while(!(TWCR & 0b10000000)); //solange warten, bis was ankommt

output = TWSR;

lcd_clrscr();
lcd_gotoxy(0,0);
lcd_puts(itoa(output, buffer, 2));

_delay_ms(300);
}

JeyBee
26.05.2010, 15:01
Okay, demfall scheint es mir, als ob ich beim Auslesen eines Bytes das vom TWI kommt noch etwas falsch verstanden zu haben.

Das Byte dass ich auslesen will (welches vom Master kommt) wird doch im TWSR Register gepseichert, sobald der TWI-Flag kommt, oder?

Beim jetzigen Code steht jetzt immer 1100000 (ja, es sind nur 7 Bits) auf dem LCD des Slaves.

Hier nochmal mein aktueller Code:



#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"

#define Dev24C02 0xA0 // EEprom twi Adresse
#define LM75 0x90 // Temperatursensor twi Adresse

void twi_slave_init(void)
{
TWAR = 0xCC;
TWCR |= (1<<TWEN) | (1<<TWEA);
}


int main(void)
{
uint8_t output;
unsigned char buffer[10];

lcd_init(LCD_DISP_ON); // LCD initialisieren
twi_slave_init(); // TWI Slave initialisieren



while(1)
{
while(!(TWCR & 0b10000000)); //solange warten, bis was ankommt

output = TWSR;

lcd_clrscr();
lcd_gotoxy(0,0);
lcd_puts(itoa(output, buffer, 2));

_delay_ms(300);
}
}

JeyBee
26.05.2010, 16:23
Achso, ich habe eben gemerkt, dass im TCSR Register ja immer nur dieser Valid Code steht. Hier kriege ich eine $60 raus, was bedeutet, dass soweit alles okay ist.

Aber in welchem register liegt jetzt das Empfangene Byte?

StevieL
26.05.2010, 17:41
Hallo,

ich programmiere zwar nur in Bascom, aber ich kann dir vermutlich trotzdem weiterhelfen.

Wenn das TWINT-Flag gesetzt ist, kannst du ja den Status aus dem Register TWSR (Bit 3 bis 7) auslesen. Status 0x60 quittierst du jetzt in dem du das TWINT-Flag zurücksetzt. Das löst ein ACK aus und es kann auf dem Bus weitergehen. Bei einem Status 0x80 (Byte angekommen) kannst du das Register TWDR auslesen. Da steckt dann dein übertragenes Byte drin. Jetzt setzt du nach dem Auslesen des Bytes das TWINT-Flag wieder zurück. Weitere Stati findest du im Datenblatt.

JeyBee
26.05.2010, 22:43
Moin,

Vielen dank Stefan, dank deiner Beschreibung habe ich es jetzt hingbekommen.

Als kleine Ergänzung: Mit dem TWINT wird nur der TWI wieder "aktiviert". Mann muss TWEA auf High setzten, dann wird das Ack zum Master geschickt.

Danke natürlich auch an yaro.


Gruss Jey

StevieL
27.05.2010, 06:54
Hallo Jey,

TWEA muss doch eigentlich nur einmal am Programmanfang gesetzt werden, damit die Hardware überhaupt ein Ack sendet. Sonst ist der Chip "virtuell vom Bus abgehängt". Das ACK wird dann automatisch gesendet, wenn du TWINT zurücksetzt. So lese ich das zumindest aus dem Datenblatt.

JeyBee
27.05.2010, 12:02
Ich bins nochmal wieder....


Folgendes Programm läuft soweit einwandfrei:


int main(void)
{
uint8_t output;
uint8_t status;
uint8_t data;
unsigned char buffer[10];

lcd_init(LCD_DISP_ON); // LCD initialisieren
twi_slave_init(); // TWI Slave initialisieren



while(1)
{

while(!(TWCR & 0b10000000)); //solange warten, bis was ankommt
status = TWSR; // Status abfragen..

TWCR &=~ (1<<TWINT); //TWINT auf 0 setzten damit TWI wieder arbeitet
TWCR |= (1<<TWEA); //TWEA auf 1 setzten um Ack zu senden

if(TWSR == 128)
{
data = TWDR;
}

lcd_gotoxy(0,0);
lcd_puts(itoa(data, buffer, 2));
lcd_gotoxy(13,0);
lcd_puts(itoa(data, buffer, 10));
_delay_ms(300);
}

}


doch wenn ich den Programmteil für das Datenempfangen in eine eigene Funktion stecke, kriege ich nicht mehr den selben Wert:


uint8_t twi_slave_recive(void)
{
uint8_t status;
uint8_t data;

while(!(TWCR & 0b10000000)); //solange warten, bis was ankommt
status = TWSR; // Status abfragen..

TWCR &=~ (1<<TWINT); //TWINT auf 0 setzten damit TWI wieder arbeitet
TWCR |= (1<<TWEA); //TWEA auf 1 setzten um Ack zu senden

if(TWSR == 128)
{
data = TWDR;
}

return data;
}


int main(void)
{
uint8_t output;
uint8_t status;
uint8_t data;
unsigned char buffer[10];

lcd_init(LCD_DISP_ON); // LCD initialisieren
twi_slave_init(); // TWI Slave initialisieren


while(1)
{
data = twi_slave_recive();

lcd_gotoxy(0,0);
lcd_puts(itoa(data, buffer, 2));
lcd_gotoxy(13,0);
lcd_puts(itoa(data, buffer, 10));
_delay_ms(300);
}

}


Was mache ich falsch?

Gruss Jey