Archiv verlassen und diese Seite im Standarddesign anzeigen : ATmega16 als TWI-Slave
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
Wahrscheinlich meintest du:
if(TWCR & 0b10000000) //Wenn TWINT = 1, dann TWSR auslesen
{
output = TWSR;
}
Gruß, Yaro
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);
}
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);
}
}
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?
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.
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
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.
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
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.