PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : TWI von ATmega8 zu ATmega8



Jimmybot
05.11.2011, 15:14
Moin Moin,
bin schon seit Wochen daran, das TWI zwischen zwe Controller an laufen zu bringen.

Dabei bin ich auf meine suche im Internet nirgendwo darauf gestoßen, wie der Slave die Daten aus dem TWDR abholt, bzw. wie er überhaupt zu programmieren ist.
^^
das ist mein Hauptproblem.

Da ich nicht weis, wie der Slave reagieren soll, weis ich noch nicht mal, ob das Programm für den Master richtig ist.

Hier mal meine C-Codes:

Master:

/*
Test Programm für TWI zwischen zwei ATmega8.
+++
Master sendet ein Byte an Slave. Byte wird an Port B über zwei Taster (B0 und B1) eingegeben und an Port D dargestellt
Über ein dritten Taser (B2) wird die TWI-Übertragung ausgeführt
+++
Slave gibt das Byte an Port B aus.
*/
#include <avr/io.h>
#include <avr\delay.h>
#define empfanger 0x10 // Empfänger Adresse (1) plus Schreibbit (0) in Hex

void send(unsigned char adres, unsigned char data) // Sende Funktion
{
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // TWI Starten, Startbedinung
loop_until_bit_is_set(TWCR,TWINT); // Warten bis fertig
PORTC=0<<PINC0; // Fehler-LED "aus"
if ((TWSR & 0xF8) != 0x08) // Fehlerausgabe, wenn ein Fehler auftritt
PORTC=1<<PINC0; // Fehler-LED "ein"
TWDR=adres; // Zieladresse ins Register schreiben
TWCR=(1<<TWINT)|(1<<TWEN); // Zieladresse senden
loop_until_bit_is_set(TWCR,TWINT); // Warten bis fertig
PORTC=0<PINC0; // Fehler-LED "aus"
if ((TWSR & 0xF8) != 0x18) // Fehlerausgabe, wenn ein Fehler auftritt
PORTC=1<<PINC0; // Fehler-LED "ein"
TWDR=data; // Daten ins Register
TWCR=(1<<TWINT)|(1<<TWEN); // Daten senden
loop_until_bit_is_set(TWCR,TWINT); // Warten bis fertig
PORTC=0<PINC0; // Fehler-LED "aus"
if ((TWSR & 0xF8) != 0x28) // Fehlerausgabe, wenn ein Fehler auftritt
PORTC=1<<PINC0; // Fehler-LED "ein"
TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN); // TWI beenden, Stopbedingung
}

int main(void)
{
DDRD=0xFF; // Port D als Ausgang
PORTD=0x00; // Port D auf Null
DDRC=0x01; // Port C0 als Ausgang
DDRB=0x00; // Port B als Eingang

int bit[8]={1,3,7,15,31,63,127,255}, a=0;
unsigned char data;

TWBR=44; // Bitraten Erzeugung
TWSR=0x01; // Vorteiler 1

while(1)
{
if(bit_is_clear(PINB,PINB0)) // ausführen, wenn PB0 0 ist
{
_delay_ms(170); // 170ms Warten (Prellen abwarten)

if(a<=6)
{
a=a+1;
PORTD=bit[a]; // Arraywert ausgeben
}
else
a=6;
}

if(bit_is_clear(PINB,PINB1)) // ausführen, wenn PB1 0 ist
{
_delay_ms(170);

if(a!=0)
{
a--;
PORTD=bit[a]; // Arraywert ausgeben
}
else
a=0;

}
if(bit_is_clear(PINB,PINB2)) // ausführen, wenn PB2 0 ist
send(empfanger, PORTD);
}
}



Slave:

/*
Test Programm für TWI zwischen zwei ATmega8.
+++
Master sendet ein Byte an Slave. Byte wird an Port B über zwei Taster (B0 und B1) eingegeben und an Port D dargestellt
Über ein dritten Taser (B2) wird die TWI-Übertragung ausgeführt
+++
Slave gibt das Byte an Port B aus.
*/

#include <avr/io.h>
#include <avr/interrupt.h>

unsigned char Daten;

int main(void)
{
DDRB=0xFF; // Port B als Ausgang
PORTB=0x00; // Port B aus Null
TWAR=0x10; // Slave Adresse 0x10
SREG=128; // Interrupts Global aktivieren

while(1)
{
PORTB=Daten; // Byte ausgeben
}
}


SIG_2WIRE_SERIAL(void) // TWI Interrupt
{
TWCR=(1<<TWEA)|(1<<TWEN); // Bestätigung senden
loop_until_bit_is_set(TWCR,TWINT); // Warten bis fertig
Daten=TWDR; // Daten aus dem Register in den Speicher
TWCR=(1<<TWEA)|(1<<TWEN); // Bestätigung senden
}



Wie gesagt, der Code vom Slave ist jetzt einfach mal frei geraten, das ich nirgend wo infos gefunden habe.

Kann mir irgend wer sagen, wie das ganze funktioniert?
Und bitte keine Links zu euren RN-Wissen artikel und Mikrocontroller.net.
Die kenne ich mittlerweile auswendig.:(

Ich bin soweit gekommen, dass die Fehler LED leuchtet, wenn ich auf den Senden-taster drücke. Das Byte kann ich auch einstellen.
Wo ist jetzt der Fehler, wo sind die Fehlern?:(

021aet04
05.11.2011, 17:31
Beim Master sind mir schon einige Fehler aufgefallen. Vielleicht ist das auch nur hier (nicht ganz zu 100% gleiche Programm wie beim AVR Studio).
Du schreibst immer "PORTC = 1<<PC0;" bzw "PORTC = 0<<PC0;". Das ist falsch.
Das sollte man so schreiben:
zum Setzen: "PORTC |= (1<<PC0);" => mit "|=" wird nur bitweise gesetzt und beim "1<<PC0" fehlt bei dir die Klammer
zum Löschen: "PORTC &= ~(1<<PC0);" => mit "&=" und "~" wird bitweise gelöscht und beim "0<<PC0" fehlt bei dir die Klammer
Das findet man z.B. im (sehr guten) AVR GCC Tutorial bei www.mikrocontroller.net

Beim Slave ist mir aufgefallen das die ISR (Interruptroutine) falsch ist.
Der Interrupt muss so aussehen: "ISR (TWSI_vect) {...}"
Bei einem Interrupt muss immer stehen "ISR (xxx_vect){}" => statt xxx muss der jeweilige Interrupt stehen wie z.B. Int0,...
Hier etwas zu Interrupts (von www.mikrocontroller.net) http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Interrupts_mit_dem_AVR_GCC_Compiler_.28Wi nAVR.29

Die einzelnen Register,... habe ich mir nicht angesehen. Im Datenblatt auf S170 ist ein Beispiel für eine I2C Übertragung (Master). Hast du schon andere I2C Hardware angesteuert (wie z.B. Portexpander)? Ich würde zuerst einen I2C Baustein ansteuern (z.B: PCF8574,...) Wenn das klappt würde ich stattdessen einen µC mit einem I2C Slave Programm (mit gleicher Adresse) ansteuern. Somit weiß man ob der Master funktioniert.

MfG Hannes

Jimmybot
10.12.2011, 21:13
Guten Abend,
so... endlich mal wieder Zeit gehabt.
Also: Habe mir ein IC geholt, dass ich 1. über TWI ansteuern kann und 2. für ein Projekt in zukunft benötige). Der IC hört auf den Namen MAX517 und wandelt 8Bit in eine Spannung von 0V bis UB.

Der Code für den Master sieht in etwa so aus:

/*
Test Programm für TWI zwischen ATmega8 und MAX517 D/A-Wandler.
+++
Master sendet ein Byte an Slave. Byte wird an Port B über zwei Taster (B0 und B1) eingegeben und an Port D dargestellt
Über ein dritten Taster (B2) wird die TWI-Übertragung ausgeführt.
+++
Slave IC: MAX517 wandelt das Byte in ein analoges Signal um.
Adresse vom IC: 0101111 (5E)
*/
#include <avr/io.h>
#include <avr\delay.h>
#define empfanger 0x5E // Empfänger Adresse (5E) plus Schreibbit (0) in Hex

void send(unsigned char adres, unsigned char data) // Sende Funktion
{
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // TWI Starten, Startbedinung
loop_until_bit_is_set(TWCR,TWINT); // Warten bis fertig

TWDR=adres; // Zieladresse ins Register schreiben
TWCR=(1<<TWINT)|(1<<TWEN); // Zieladresse senden
loop_until_bit_is_set(TWCR,TWINT); // Warten bis fertig

TWDR=0x0; // Command-Byte ins Register. Bei MAX517: 0! Siehe Datenblatt
TWCR=(1<<TWINT)|(1<<TWEN); // Command-Byte senden
loop_until_bit_is_set(TWCR,TWINT); // Warten bis fertig

TWDR=data; // Daten-Byte ins Register
TWCR=(1<<TWINT)|(1<<TWEN); // Daten senden
loop_until_bit_is_set(TWCR,TWINT); // Warten bis fertig

TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN); // TWI beenden, Stopbedingung
}

int main(void)
{
DDRD=0xFF; // Port D als Ausgang
PORTD=0x00; // Port D auf Null
DDRB=0x00; // Port B als Eingang

unsigned char data, a=0;

TWBR=60; // Bitraten Erzeugung
TWSR=0; // Vorteiler 1

while(1)
{
if(bit_is_clear(PINB,PINB0)) // ausführen, wenn PB0 0 ist
{
_delay_ms(170); // 170ms Warten (Prellen abwarten)

if(a<=255)
{
a=a+1;
PORTD=a; // Wert ausgeben
}
else
a=255;
}

if(bit_is_clear(PINB,PINB1)) // ausführen, wenn PB1 0 ist
{
_delay_ms(170);

if(a!=0)
{
a--;
PORTD=a; // Wert ausgeben
}
else
a=0;

}
if(bit_is_clear(PINB,PINB2)) // ausführen, wenn PB2 0 ist
send(empfanger, PORTD);
}
}



Okay...
Jetzt zurück zu mein Problem:
Master Code, würde so funktionieren (Statt den Command-Byte würde ein Datenpaket zum Slave-AVR gesendet).
Aber wie bringe ich nun den Slave AVR dazu, dass er funktioniert?
Ich weis, dass die TWI ein Interrupt auslöst, wenn der Slave sich angesprochen fühlt.
Aber wie müsste ein C-Code aussehen, der die Daten aus dem Register holt und in ein Array Speichert?

oberallgeier
10.12.2011, 23:47
... wie das ganze funktioniert? Und bitte keine Links zu euren RN-Wissen ...Das verstehe ich jetzt nicht. Der Code vom SlaveBeispiel im "TWI Slave mit a v r - g c c" läuft doch einwandfrei ! Zumindest bei mir (https://www.roboternetz.de/community/threads/55744-I²C-Master-m328-kann-Slave-m328-nicht-lesen) zwischen zwei m328ern. Und - soweit ich es nachgesehen hatte - heissen die Registernamen fürs TWI auf den A tmel megas immer gleich.