Hallo, ich möchte eine bidirektionale Kommunikation von einem Mega328
mit einem Mega 168 herstellen.
Als Treiber benutze ich einen SN75176, meine Sprache ist C.
Nun habe ich festgestellt, das ich zwischen den Umschalten von Senden
auf Empfang einen Delay einfügen muss, da sonst Bytes abgeschnitten
werden.
Der UART Code inclusive Delays ist auf beiden µC gleich.
Die Kommunikation beobachte ich über einen RS485 auf RS232 Wandler auf
meinem Laptop mit HTERM. Dort sehe ich auch, das zuerst alles
funktioniert, und nach einer kleinen Laufzeit (wärme?) überträgt er
nurnoch Mist. Ich vermute das er nicht schnell genug auf Empfang
wechselt, und deshalb Bits abgeschnitten werden.
Ich empfange über eine ISR in einen Ringpuffer, was auch ohne weiteres
funktioniert.
Ob per Interrupt oder nicht - jedenfalls muss man auf TXC warten, bevor
man die Richtung umschaltet. Nicht schon, wenn das letzte Byte im Puffer
gelandet ist.
A. K. schrieb:> Stimmt, allerdings wäre das an anderer Stelle besser> untergebracht.
Ich bin den Ablauf schritt für schritt durchgegangen und sehe nicht, wo
er vorzeitig auf Senden umschaltet. Wo meinst du denn wo es besser
untergebracht wäre?
DrWright schrieb:> Wo meinst du denn wo es besser untergebracht wäre?
Üblich ist es nach der while-Schleife vor der Richtungsumschaltung. TXC
wird erst gesetzt, wenn Puffer und Schieberegister leer sind.
Im gezeigten Code wird der Tx-Puffer Daten verlieren, wenn die Bytes
schneller dort landen als sie übertragen werden. Wird das im nicht
gezeigten Code irgendwie verhindert/vermieden?
Ich habe keine Pullups oder einen 120 Ohm Abschlusswiderstand eingebaut.
Hab mitm Oszi nachgemessen, und der Ausgang ist stabil, es floatet also
nichts. Der TX Buffer ist groß genug, ich schicke nur alle 2 sek 4 byte.
Habe den Code daraufhin so geändert.
1
voiduart_txd_Do(void)
2
{
3
while(txd_do_cnt!=txd_buffer_cnt)// Daten zum Senden vorhanden?
4
{
5
if(UCSR0A&(1<<UDRE0))// Sendepuffer bereit?
6
{
7
if(!(DIRBIT_DDI&(1<<DIRBIT_PIN)))
8
{
9
_delay_ms(5);
10
DIRBIT_PORT|=(1<<DIRBIT_PIN);// DIRBIT auf Senden
11
_delay_us(100);
12
}
13
UDR0=txd_buffer[txd_do_cnt];
14
txd_do_cnt++;
15
if(txd_do_cnt==buffersize){txd_do_cnt=0;}
16
}
17
}
18
19
if(DIRBIT_DDI&(1<<DIRBIT_PIN))// Empfangsbit schon umgeschaltet?
20
{
21
while(!(UCSR0A&(1<<TXC0)));// Warte bis Zeichen gesendet ist
22
UCSR0A|=(1<<TXC0);// Gesendet Bit löschen
23
24
_delay_us(150);
25
DIRBIT_PORT&=~(1<<DIRBIT_PIN);// Auf Empfang schalten
26
_delay_us(100);
27
}
28
}
Das hat leider auch nichts gebracht. Das merkwürdige ist ja das es
einige Zeit funktioniert und dann langsam falsche bytes geschickt
werden.
Ich versuche trotzdem mal Pullup/Down widerstände Einzulöten. Mal sehen
ob es was bringt.
Habe nun 2 kOhm Widerstände als Terminierung genommen. Leider hat sich
das Problem damit nicht gelöst. Es scheint mir ein thermiches Problem zu
sein. Beim ersten Test wenns noch kalt ist gehts ohne Probleme und nach
einiger Zeit tritt der Fehler dann auf. Im HTERM kann ich beobachten das
er bei manchen Bytes das erste Bit High setzt, obwohl es Low sein
sollte.
So, ich habe das Problem beheben können indem ich erstmal alle Delays
entfernte und getestet habe welche überhaupt notwendig sind.
Es reicht ein 5ms Delay vor dem ersten Umschalten auf Sendebetrieb.
1
voiduart_txd_Do(void)
2
{
3
while(txd_do_cnt!=txd_buffer_cnt)// Daten zum Senden vorhanden?
4
{
5
if(UCSR0A&(1<<UDRE0))// Sendepuffer bereit?
6
{
7
if(!(DIRBIT_DDI&(1<<DIRBIT_PIN)))
8
{
9
_delay_ms(5);
10
DIRBIT_PORT|=(1<<DIRBIT_PIN);// DIRBIT auf Senden
11
}
12
UCSR0A|=(1<<TXC0);// Gesendet Bit löschen
13
UDR0=txd_buffer[txd_do_cnt];
14
txd_do_cnt++;
15
if(txd_do_cnt==buffersize){txd_do_cnt=0;}
16
}
17
}
18
19
if(DIRBIT_DDI&(1<<DIRBIT_PIN))// Empfangsbit schon umgeschaltet?
20
{
21
while(!(UCSR0A&(1<<TXC0)));// Warte bis Zeichen gesendet ist
22
UCSR0A|=(1<<TXC0);// Gesendet Bit löschen
23
DIRBIT_PORT&=~(1<<DIRBIT_PIN);// Auf Empfang schalten
24
}
25
}
26
27
uint8_tuart_SendByte(uint8_tin)
28
{
29
txd_buffer[txd_buffer_cnt]=in;
30
txd_buffer_cnt++;
31
if(txd_buffer_cnt==buffersize){txd_buffer_cnt=0;}
32
returnin;
33
}
Ganz wichtig ist auch das TX Complete Bit.
Vielen Dank für die Hilfe
Ich habe festgestellt, das ich nach jedem Byte ein Umschalten auf
Empfang notwendig ist, da sonst ein Frame Error vom empfangenden Byte
erzeugt wird.
(Ich kommuniziere mit einer Steuerung deren Code in Assembler
geschrieben wurde, das ACK kommt sehr schnell).
Beschalte doch den 485-Transceiver so, dass Du immer empfängst, auch
Deine eigenen Daten. Erstens weißt Du somit genau, wenn das Byte
gesendet worden ist, und Du weißt genau, dass das Byte korrekt gesendet
worden ist und nicht irgendwer anders den Bus belegt hat.
fchk
Hallo,
DrWright schrieb:> Ich habe festgestellt, das ich nach jedem Byte ein Umschalten auf> Empfang notwendig ist, da sonst ein Frame Error vom empfangenden Byte> erzeugt wird.
sollte dies wirklich der Fall sein dann hast du was Grundlegendes falsch
gemacht!
Ich hab jetzt alle vorhergehenden Mails überflogen und ich denke dein
Problm ist weniger ein Timing-Problem als vielmehr ein Problem der
"Stabilität".
Kurz: Du hast keine stabilen Verhältnisse in deiner Schaltung.
Ob dies der Fall ist oder nicht kannst du ganz einfach testen. Ein
reines Umschalten von Empfang auf Senden und umgekehrt darf keinen
Zustandswechsel auf den Leitungen DI, DO, A und B verursachen.
Ein Zustandswechsel würde Dir unweigerlich ein Startbit (und damit ein
Zeichen) vorgaukeln.
Der Ruhezustand für DI und DO muss high sein und für A/B muss gelten
A-B>200mV.
Damit der Ruhezustand auf diesen Leitungen sicher ist schlage ich dir
obige Schaltung vor die du auch in diversen Foren wiederfindest.
Das denke ich langsam auch, R1 und R3 habe ich bereits, auf die
Terminierung habe ich verzictet, weil die Leitung grad mal 1 m lang ist.
Den Pullup an RO habe ich noch nicht. Ich werde Testhalber mal die
Richtung umschalten lassen im sekundentakt und dann einfach mal mitm
Oszi Messen.
Ich denke das sollte es gewesen sein, vielen dank für die Info.
Ich hab jetz auf RXD den Pullup eingeschaltet, ohne Pullup ist der von
0,8-4,6V beim Umschalten gefloatet, mit aktiven Pullup bleibt er starr
bei 4,7V stehen.