PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 2 MEGA8 mit UART



bertl100
28.03.2005, 16:50
Hallo Leute!

Kann mir jemand bei meiner Kommunikation zwischen 2 ATMega8
helfen?
Ich möchte die beiden über UART kommunizieren lassen, allerdings nur einzelne, zeitlich definierte Befehle
Der Erste Mega hat eine Verbindung zum Pc und gleichzeitig zum zweiten Mega.
Da beide als Master arbeiten müssen kommt SPI pder TWI(I2C) nicht in Frage

Nun aber zur den eigentlichen Fragen.
Kann ich eine Verbindung so realisieren?
Reicht es wenn ich einfach RxD nach TxD zu umgekehrt verbinde?

uwegw
28.03.2005, 17:27
Reicht es wenn ich einfach RxD nach TxD zu umgekehrt verbinde?

zumindestens in eine richtung hab ich sowas schon mal erfolgreich benutzt... zwischen den megas ist nicht so das problem, aber ich weiß nicht was passiert wenn auch der pc noch dazugeschaltet wird... das wär in meine augen der kritischere teil der ganzen geschichte...

pebisoft
28.03.2005, 17:55
es geht nur , wenn du mit bascom eine software-rs232 erstellst.
rxd/txd können immer nur mit einer stelle verbunden werden.
mit der softwareschnittstelle (andere pin festelgen als rxd/txd) geht
es mit bascom. in winavr-c noch nicht.
mfg pebisoft

PicNick
28.03.2005, 18:36
Du kannst eine TX->RX / TX->RX / TX->RX Kette bilden, allerdings brauchst du da ein bißchen Protokoll.

Rodney
28.03.2005, 18:52
Du kannst eine TX->RX / TX->RX / TX->RX Kette bilden, allerdings brauchst du da ein bißchen Protokoll.

wär wahrscheinlich die technisch einfachste Lösung, einfach als erstes Byte ne ID übertragen die den Empfänger kennzeichnet und nen Stopbyte, fertig.
Der große Vorteil hierbei wäre, das es sehr gut erweiterbar ist.

bertl100
28.03.2005, 19:30
Hab gerade gesehen, dass der Mega64 2 USARTs hat.
Wäre doch sicher einfacher.
Ich muß mit einem Controller viele Messungen durchführen und das Ganze dann noch interruptgesteuert zu programmieren wäre wahnsinn.
Das zu prüfende Medium muß zwischen mehreren Betriebszuständen wechseln und mein Controller muß dann natürlich auch zu einer anderen Function oder Sub springen. Da bleibt mir keine andere Wahl als mit USART zu kommunizieren.
Da ich mich bei Protokollen nicht wirklich auskenne und mein Zeitplan schon sehr knapp ist werde ich auf den 64er umsteigen.
Falls ihr da ein Problem seht dann bitte meldet euch.
Danke!!!

Pascal
28.03.2005, 22:08
Da beide als Master arbeiten müssen kommt SPI pder TWI(I2C) nicht in Frage

I²C ist aber ein Multimasterbus, folglich wäre auch die Verbindung per TWI möglich

bertl100
28.03.2005, 22:43
Wenn ich zwei aktive Bausteine wie uc und uc per I2C verbinden würde,
müsste ich einen zwangsläufig als slave deklarieren. Bei I2C gibt es zwar den Multimastermodus, dieser ist aber, soweit ich weiß, nur zum beschreiben und auslesen von passiven Bauteilen geeignet.

PicNick
29.03.2005, 11:04
Multimaster heißt nur, daß mehrere Geräte den Bus übernehmen können. WAS die dann damit tun, ist ihre Sache.
Klingt aber so, als brauchst du gewißermaßen Zwitter, mal Master, mal Slave.
Wenn mehrere Geräte in einen System miteinander kreuz und quer miteinander quatschen wollen, wirst du dich mit entsprechenden Protokollen auseinandersetzen müssen, da helfen dir mehrere UART's auch nix. Das Problem ist ja nicht elektrisch, sondern logisch.
Schau dir eine Talkshow im Fernsehen an. Wenn da nicht irgendwas oder -wer eine Kontrolle ausübt, herrscht Chaos.

Pascal
29.03.2005, 11:06
klar muss ein µC der Slave sein, wenn der andere der Master ist, allerdings kann der Master den Bus wieder freigeben, wenn er mit dem Senden fertig ist, so dass der µC, der zuerst Slave war, zum Master werden kann

PicNick
29.03.2005, 11:20
Klaro, jetzt haben wir eine Runde, wo jeder mal reden kann. Aber wenn z.B. zwei Master (o.k, nacheinander) dem dritten gegenseitig die register und commands niederschreiben, kann es haarig werden.

bertl100
29.03.2005, 14:55
Wie könnte ich den nbei I2C den Mega8 eine Slaveadresse geben.
Das Register ist bei mir nicht verfügbar. Ich hab gelesen, dass es eine eigene
Library in Bascom gibt, mit der ich mit Hi-Level-Befehlen arbeiten kann.
Oder wenn jemand einen Beispielcode für den Slavebetrieb hat, wäre ich sehr dankbar.
Ich möchte damit Single-Werte und Befehle, also Strings an den anderen übertragen.

PicNick
29.03.2005, 15:00
Bei Atmega... heißt der I2C TwoWireSerialInterface (TW)
Der mega8 hat alle register (samt Slave Addr), die der Mensch braucht und die sind im Datasheet recht genau beschrieben

bertl100
29.03.2005, 15:32
wenn ich es schaffe den mc eine slaveadresse zu geben, wohin wird dann das byte das ich sende im anderen mc geschrieben?
By the way, die Subroutinen für die TWI funktioniernen bei mir.
Habe schon externe serielle eeprom´s beschrieben und ausgelesen.
Nur wie das mei 2 mc´s geht weis ich nicht.
Logischerweise würde ich vermuten, dass die byte´s in den eigenen eeprom
geschrieben werden mir einer adresse die ich bei der twi angebe.
Ist das richtig so?

PicNick
29.03.2005, 15:47
"SLAVE" heißt, daß er einen Interrupt startet, wenn irgendein Master deine Adresse in den Bus geschrieben hat. (+ R/W)
WAS der slave mit den empfangenen Bytes macht, und als was er sie interpretiert, hängt von ihm ab. Schau dir z.B. die diversen I2C Peripheriegeräte an, da siehst du ja, was alles möglich ist.

muraad
01.04.2005, 16:06
Ja PicNick hat recht. Es wird einfach ein TWI Interrupt gestartet. Dort kann man das TWBR Register abfragen.
Theoretisch hab ich sowas mal gemacht mit WinAVR. Vielleicht hilfts dir.
Es gibt 5 read only Register und 5 write only Register.


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

#define i2c_slave_init TWCR= _BV(TWEA) | _BV(TWEN) | _BV(TWIE)
// Slave init und i2c Interrupt enable

#define slave_addr_init TWAR |= _BV(TWA0)
// Slave addresse auf 0x10 also auf 10, keine reaktion auf globale anfragen

// Die read_only Register werden im Hauptprogramm regelmäßig mit z.B. Sensorwerten aktuallisiert
// Die write_only Register werden regelmäßig im Hauptprogramm ausgelesen um auf deren Werte zu reagieren
volatile unsigned char read_register1,read_register2,read_register3,read_ register4,read_register5;
volatile unsigned char write_register1,write_register2,write_register3,wr ite_register4;
volatile unsigned char regwrite_flag=0;
volatile unsigned char regvalue=0;

SIGNAL(SIG_2WIRE_SERIAL)
{
if(TWSR==TW_SR_SLA_ACK|TWSR==TW_SR_ARB_LOST_SLA_AC K|TWSR==TW_SR_DATA_ACK) // Slave Reciever Datenpaket empfangen
{
if(regwrite_flag==1)
{
if(regvalue==6){
write_register1=TWDR;
regwrite_flag=0;
regvalue=0;}
if(regvalue==7){
write_register1=TWDR;
regwrite_flag=0;
regvalue=0;}
if(regvalue==8){
write_register1=TWDR;
regwrite_flag=0;
regvalue=0;}
if(regvalue==9){
write_register1=TWDR;
regwrite_flag=0;
regvalue=0;}
if(regvalue==10){
write_register1=TWDR;
regwrite_flag=0;
regvalue=0;}
}
else
{
if(TWDR==1){ // Register 1 until 5 only read;
TWDR=read_register1;
TWCR|=(1<<TWINT);}
else if(TWDR==2){
TWDR=read_register2;
TWCR|=(1<<TWINT);}
else if(TWDR==3){
TWDR=read_register3;
TWCR|=(1<<TWINT);}
else if(TWDR==4){
TWDR=read_register4;
TWCR|=(1<<TWINT);}
else if(TWDR==5){
TWDR=read_register5;
TWCR|=(1<<TWINT);}
else if(TWDR==6||TWDR==7||TWDR==8||TWDR==9||TWDR==10){ // Register 6-10 write only register.
regwrite_flag=1; // Flag wird gesetzt damit beim nächsten mal der TWDR Wert als Registerinhalt
regvalue=TWDR; // und nicht als Registernummer interpretiert wird.
TWCR|=(1<<TWINT);}


// Hier könnte man noch weiter Befehle eingeben die dann mit der Entsprechenden TWDR ausgeführt werden
}
}
else if(TWSR==TW_SR_DATA_NACK)
TWCR = (1<<TWINT) | (1<<TWEA);
else if(TWSR==TW_ST_SLA_ACK|TWSR==TW_ST_ARB_LOST_SLA_AC K|TWSR==TW_ST_DATA_ACK) // Dann ist Slave Transmitter mode und es wird einfach das byte in TWDR
TWCR |= (1<<TWINT); // Versand
else if(TWSR==TW_ST_DATA_NACK|TWSR==TW_ST_LAST_DATA)
TWCR = (1<<TWINT) | (1<<TWEA);
else if(TWSR==TW_SR_STOP) // STOP condition has been recevied
TWCR=(1<<TWINT) | (1<<TWEA);
TWCR |= 0b10000000;
}


void main(void)
{
i2c_slave_init;
slave_addr_init;
for(;;)
{
/* read_register1= ;
read_register2= ;
read_register3= ;
read_register4= ;
read_register5= ;

if(write_register1== )

if(write_register2== )

if(write_register3== )

if(write_register4== )

if(write_register5== )

*/
}
}

Ich hab auch mal was für SPI geschrieben. Dabei können beide Master und Slave werden. Allerdings auch nur theoretisch, also ich hatte noch keine Möglichkeit es zu testen. Hab leider keine zwei ATmega.



/* Es gibt hier keinen Slave oder Master. Beide können beides werden. Es wird jeweils der SS_Master
Pin des einen mit dem SS_Slave Pin des anderen verbunden. In SPI_init wird der SS_Master Pin auf
high gesetzt womit der SS_Slave Pin(SSPin/PB4 beim ATMEga32) des anderen auf high ist. In
SPI_Transmitt wird der SS_Master auf low gesetzt und damit SS_Slave des anderen auch auf low.
Damit geht der mit SS_Slave auf low in den Interrupt. Im Interrupt werden erst die angekommenen
Daten dem Empfangsbuffer angehängt, dann wird wieder in den Master Modus geschaltet, außer der
SS_Slave Pin ist noch auf low, d.h. der aktuelle Master will noch was senden.
Wird etwas versand geht der andere Mikrocontroller in den Interrupt
und bei ihm geschieht das gleiche.

*/

#include <avr/io.h>

#define SS_Master PB3 // Pin zum Slave
#define SS_Slave PB4 // Pin vom Slave
#define MOSI PB5
#define MISO PB6
#define SCK PB7
#define DDR_SPI DDRB
#define PORT_SPI PORTB
#define MAX 99 // Bytes des SPI Lesebuffers max. 255 !! 255 sind 256Bytes

volatile unsigned char data;

volatile unsigned char Buffer[MAX]; // Empfangs buffer
volatile unsigned char Buffer_count=0; // Wieviele Bytes sind im Buffer

SIGNAL (SIG_SPI) // SPI Recieve
{
data=SPDR; // SPI Datenregister in data laden.
Buffer[Buffer_count]=data; // data in Buffer laden
Buffer_count++; // 1 Byte mehr im Empfangsbuffer

// Prüfen ob SS_Slave schon wieder high ist --> empfang vorbei
if(PORT_SPI & (1<<SS_Slave))
{
// Wieder Master werden
SPCR|=(1<<MSTR);
// Daten versenden oder gleich raus aus Interrupt und nur wieder Master
// SPI_Transmitt(' ');
}
}



void SPI_Init(void)
{
// Set MOSI and SCK output, all others input
DDR_SPI = (1<<MOSI) | (1<<SCK) | (1<<SS_Master);
PORT_SPI|=(1<<SS_Master); //SS Pin zum SPI Slave auf high
// SPI enable, Master enable, fck/16, SPI Interrupt enable
SPCR= (1<<SPE) | (1<<MSTR) | (1<<SPR0) | (1<<SPIE);
}

unsigned char SPI_getc(void) // holt das letzte Byte seit dem letzten Aufruf
{
unsigned char data,i=1;
if(Buffe_count!=0) // Neue Daten seit dem letzten Aufruf
{
data = Buffer[0];
// Buffer neu ordnen damit letztes Byte wieder auf Buffer[0] ist.
for(i;i<=Buffer_count;i++)
Buffer[i-1]=Buffer[i];
Buffer_count--; // 1 Byte weniger im Empfangsbuffer
return data;
}
}

void SPI_Transmitt_Raw(unsigned char data) // Sollte im eigenen Programm nicht verwendet werden
{
SPDR = data;
while(!(SPSR & (1<<SPDIF))) asm volatile ("nop");
}

void SPI_putc(unsigned char data) // Das ist die Funktion um ein Byte zu senden
{ // z.B. SPI_putc('c'); --> sendet ein c
// unsigend char c;
PORT_SPI &= ~(1<<SS_Master); // SPI_putc(c); --> sendet den Inhalt der Variable c
SPDR = data;
while(!(SPSR & (1<<SPDIF))) asm volatile ("nop");
PORT_SPI|=(1<<SS_Master);

}

void SPI_puts (unsigned char *s) // sendet einen Buffer aus mehreren Bytes
{ // z.B. SPI_puts("hallo"); --> ist aber blödes Beispiel mit hallo
PORT_SPI &= ~(1<<SS_Master); // unsigned char buffer[100];
while (*s) // SPI_puts(buffer)
{ /* so lange *s != NULL */
SPI_Transmitt_Raw(*s);
s++;
}
PORT_SPI|=(1<<SS_Master);
}

Also vielleicht hilfts dir ja weiter, wenn du kein C dann ist es näturlich schade.
Gruß Muraad