- Labornetzteil AliExpress         
Ergebnis 1 bis 9 von 9

Thema: ATmega16 als TWI-Slave

  1. #1
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    10.02.2007
    Beiträge
    277

    ATmega16 als TWI-Slave

    Anzeige

    LiFePo4 Akku selber bauen - Video
    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.

    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)
    	{
    		
    		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

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    34
    Beiträge
    607
    Wahrscheinlich meintest du:

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

    Gruß, Yaro

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    34
    Beiträge
    607
    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);
    }

  4. #4
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    10.02.2007
    Beiträge
    277
    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:

    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);
    	}
    }

  5. #5
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    10.02.2007
    Beiträge
    277
    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?

  6. #6
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    09.05.2007
    Beiträge
    202
    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.
    Gruß, Stefan

  7. #7
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    10.02.2007
    Beiträge
    277
    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

  8. #8
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    09.05.2007
    Beiträge
    202
    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.
    Gruß, Stefan

  9. #9
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    10.02.2007
    Beiträge
    277
    Ich bins nochmal wieder....


    Folgendes Programm läuft soweit einwandfrei:
    Code:
    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:
    Code:
    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

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen