Hallo zusammen,
ich habe die USART lib von Fleury auf einem ATMEGA88 mit 16MHz Quarz
laufen. Der befeuert einen RS485 Transceiver (LT1785). Die Busleitungen
sind mit einem VC 0805-14 Varistor geschützt.
Über einen USB - RS485 Converter (Digitus DA70157) gehe ich dann in den
PC aufs Hyperterminal.
Das Ganze lief auf Anhieb, allerdings nur bis 115200 Bit/s. Bei höheren
Datenraten gibts Datensalat.
Und ab da stehe ich auf dem Schlauch.
Ich muss für ein Projekt 1MBbit/s in den Controller einlesen, wollte das
zumindest mal bis 921600Bit/s auf dem Rechner testen.
Meine Oszi Ausstattung lässt leider keine weitere Analyse zu. Wo könnte
das Problem liegen?
- Kapazität auf der Leitung sollte Ok sein.
- Oh, ich seh grade, Terminierung könnte das Problem sein. Ich hab
derzeit nichts dran, Leitung ist aber auch nur 20cm lang.
- sind irgendwelche Fallstricke in der lib vorhanden, die ich übersehen
habe?
- andere Ideen?
Viele Grüße + herzlichen Dank für Eure Hilfe!
Volker
Hallo Tosa,
herzlichen Dank für den Tip, das war es natürlich.
Jetzt habe ich leider ein neues Problem, vermutlich ähnlich trivial?!
Ich kann nun einen String, Char, alles was das Fleury Beispielprogramm
hergibt, ausgeben.
Aber wenn ich einen Char einlese und dieses als Echo wieder ausgebe,
kommt nur Murks im Terminal an.
Das Programm habe ich denke ich verstanden, unsigned int wird auf
unsigned char gecastet, damit die Diagnosebits abgeschnitten werden und
dann wird das Byte zurückgeschrieben.
Irgendwo beim einlesen muss ein Fehler drin sein, denn
1
uart_putc('x');
funktioniert ja.
Hat jemand eine Idee, wie da heranzugehen ist?
Grüße,
Volker
Vo M. schrieb:> Aber wenn ich einen Char einlese und dieses als Echo wieder ausgebe,> kommt nur Murks im Terminal an.> Das Programm habe ich denke ich verstanden, unsigned int wird auf> unsigned char gecastet, damit die Diagnosebits abgeschnitten werden und> dann wird das Byte zurückgeschrieben.
Ja.
Aber nur dann, wenn in den Diagnosebits auch steht, dass ein Zeichen
vorhanden ist.
> Irgendwo beim einlesen muss ein Fehler drin sein, denn
Der Fleury Code funktioniert. Den haben viele im Einsatz.
Also muss der Fehler vorrangig mal in deinem Code zu suchen sein.
> Hat jemand eine Idee, wie da heranzugehen ist?
Ja.
Wie immer. Den Code posten.
Vo M. schrieb:> mit 16MHz QuarzVo M. schrieb:> 921600Bit/s
Das ergibt 8,5% Fehler, viel zu hoch.
Bei hohen Baudraten mußt Du Quarze nehmen, die ganzzahlige Teiler
bilden.
Bei 921600Baud geht daher nur 14,7456MHz.
Peter
Karl Heinz Buchegger schrieb:
>Der Fleury Code funktioniert. Den haben viele im Einsatz.
Das kann nicht sein
Es gibt auch unzählige wo es nicht geht.
Leider gibt es auch kein Beispiel auch hier nicht ausser das
mitgelieferte wo, zb. Daten ins Array geschrieben
werden.
http://www.gjlay.de/helferlein/avr-uart-rechner.html
Auf der Seite kannst du sehen, mit welchem Quarz du welche Baudrate
hinbekommst, ohne das der Fehler zu gross wird.
RS232/485 verwendet asynchrone datenübertragung, sodass die Bitlänge auf
2% genau sein muss, damit der Empfänger auch wirklich jedes bit
mitbekommt und nichts verschluckt.
Gustav schrieb:> Karl Heinz Buchegger schrieb:>>>Der Fleury Code funktioniert. Den haben viele im Einsatz.>> Das kann nicht sein> Es gibt auch unzählige wo es nicht geht.
Und wo ist dein Beispiel eines nicht funktionierenden Codes?
Erst mal ist nicht klar, warum es da überhaupt einen Unterschied geben
soll. Der Fleury Code liefert die empfangenen Zeichen. Nicht mehr und
nicht weniger. Wenn in der Weiterverarbeitung der Zeichen ein Fehler
ist, dann kannst du das wohl schlecht dem Fleury Code anlasten. So
gesehen ist es völlig egal, was du mit den Zeichen weiter machst - das
ist erst mal dein Bier und bis zum Beweis des Gegenteils nicht dem
Fleury Code anzulasten.
> Leider gibt es auch kein Beispiel auch hier nicht ausser das> mitgelieferte wo, zb. Daten ins Array geschrieben> werden.
Was genau stellt dich da vor Probleme?
1
charReceivedLine[80];
2
uint8_tnextReceivedChar;
3
uint8_treceivedLineFinished;
4
uint8_tuartError;
5
6
uint8_tHandleUART()
7
{
8
unsignedintc=uart_getc();
9
10
if(c&UART_NO_DATA)
11
return;
12
13
if((c&UART_FRAME_ERROR)||
14
(c&UART_OVERRUN_ERROR)||
15
(c&UART_BUFFER_OVERFLOW)){
16
uartError=TRUE;
17
return;
18
}
19
20
if(nextReceivedChar>=sizeof(ReceivedLine)-1){
21
uartError=TRUE;
22
nextReceivedChar=0;
23
}
24
25
ReceivedLine[nextReceivedChar++]=c;
26
ReceivedLine[nextReceivedChar]='\0';
27
28
if(c=='\n')
29
receivedLineFinished=TRUE;
30
else
31
receivedLineFinished=FALSE;
32
33
returnreceivedLineFinished;
34
}
Was genau soll da jetzt in der Fleury Lib ein Problem machen?
Immer schön brav nach jedem uart_getc die Flags auswerten, dann kann es
da keine Probleme mit der Lib geben. Eagl, wie man dann die Zeichen
weiter auswertet und zb sukzessive in einem Array speichert.
PS: Was reguläre Poster nicht sehen können.
Da gibt es noch einen gelöschten Post, indem Volker bestätigt, dass
nicht der Fleury Code schuld war, sondern dass er vergessen hatte, die
RS485 entsprechend umzustellen.
Lernender schrieb:> Wie muss mann die "flags" in der Mainloop auswerten
Ähm.
Verarscht du mich jetzt?
Schon mal das Beispiel angesehen, welches Peter mitliefert?
Bzw. was könnte wohl das hier
1
unsignedintc=uart_getc();
2
3
if(c&UART_NO_DATA)
4
return;
5
6
if((c&UART_FRAME_ERROR)||
7
(c&UART_OVERRUN_ERROR)||
8
(c&UART_BUFFER_OVERFLOW)){
9
uartError=TRUE;
10
return;
11
}
sein, bzw. welche Aufgabe könnte das wohl im Zusammenhang mit dieser
Funktion erfüllen?
Lernender schrieb:> nein ich will hier niemand Verarschen>> so hab ich das bei mir,> nach Peter Fleury seinem Beispiel
Na so ganz ist das nicht das Beispiel :-)
Du pruefst zwar auf die Fehlerzustaende, am Ende verwendest Du aber
dennoch 'c' um es in Dein Array zu packen. Egal ob ein Fehler
aufgetreten ist oder nicht.
Mach es so wie Karl Heinz es vorgeschlagen hat:
Thomas hat ja zu einem Teil schon was gesagt.
Weiters
1
while((c=uart1_getc())!=55&&next<sizeof(Message))
2
{
3
Message[next++]=c;
4
}
Welchen Teil des Satzes ...
"Immer schön brav nach jedem uart_getc die Flags auswerten, dann kann es
da keine Probleme mit der Lib geben."
... hast du jetzt nicht verstanden?
Da, in dieser Schleife, ist ein uart_getc (ok, ein uart1_getc). WO
wertest du die Flags aus, ob dieser Aufruf von uart1_getc überhaupt ein
Zeichen geliefert hat?
Du musst schon nach den Regeln spielen! Das kann man wohl kaum der
Fleury Lib anlasten, wenn du nicht gewillt bist, dich daran zu halten
oder nicht verstehst, dass uart_getc dir mit seinem Returnwert mehrere
Dinge mitteilen kann. Unter anderem den, dass zur Zeit eben kein Zeichen
an der UART vorlag. Du scheinst das überhaupt nicht verstanden zu haben,
dass dieses uart_getc aus der Fleury Lib eben NICHT wartet, bis ein
Zeichen vorliegt, sondern dem Aufrufer mit dem Returnwert schlicht und
ergreifend mitteilt: "Ich hab (noch) nichts. Probiers später nochmal. In
der Zwischenzeit kannst du ja ruhig was anderes rechnen, wenn du
möchtest."
// Der Mc ist nunmal schneller als die Schnittstelle :-)
11
}
12
else{
13
// kein Fehler und es liegt auch ein Zeichen vor.
14
Message[next++]=c;
15
}
16
}while(c!=55&&next<sizeof(Message));
Das ist kein schoener Code, aber er soll Schritt fuer Schritt beleuchten
wie man es machen koennte. Eventuell solltest Du noch vorsehen das Du
nur Fehler bekommst (falsche Baudrate z.B.). Dann hast Du eine
Endlosschleife weil die Abbruchbedingung nie erfuellt wird.
Karl Heinz Buchegger schrieb:> Thomas hat ja zu einem Teil schon was gesagt.>> Weiters while( ( c = uart1_getc() ) != 55 && next< sizeof(Message) )> {> Message[ next++ ] = c;> }>> Welchen Teil des Satzes ...> "Immer schön brav nach jedem uart_getc die Flags auswerten, dann kann es> da keine Probleme mit der Lib geben."> ... hast du jetzt nicht verstanden?
Es wird so lange eingelesen bis das Ende-Zeichen 55 kommt.
oder ist das nicht richtig
1
//Mainlloop
2
dat=uint8_tgetdata()//wird von von der Mainloop aufgerufen
Lernender schrieb:> Karl Heinz Buchegger schrieb:>> Thomas hat ja zu einem Teil schon was gesagt.>>>> Weiters while( ( c = uart1_getc() ) != 55 && next< sizeof(Message) )>> {>> Message[ next++ ] = c;>> }>>>> Welchen Teil des Satzes ...>> "Immer schön brav nach jedem uart_getc die Flags auswerten, dann kann es>> da keine Probleme mit der Lib geben.">> ... hast du jetzt nicht verstanden?>>>> Es wird so lange eingelesen bis das Ende-Zeichen 55 kommt.> oder ist das nicht richtig
Aber der springende Punkt ist, dass nicht jeder Aufruf von uart1_getc
ein Zeichen liefert!
Der µC ist hunderte male schneller, als Zeichen auf der Schnittstelle
übertragen werden können!
Ist wie bei deinem Postkasten.
Du kannst alle 2 Minuten zum Postkasten laufen. Aber das bedeutet NICHT,
dass da jedesmal ein Brief drinnen ist!
Sieh dir doch mal das Fleury Beispiel GENAU(!) an.
c = uart_getc();
if( c & UART_NO_DATA )
{
}
else
....
was könnte wohl UART_NO_DATA heissen?
No Data - keine Daten
"Ich hab momentan nichts! Da ist nichts was du verarbeiten könntest!"
Eben "No Data"
Das scheint dich aber nicht weiter zu stören. Du speicherst trotzdem
irgendwas ab. Selbst wenn auf der UART die Zeichen noch gar nicht da
sind.
> while( ( c = uart1_getc() ) != 55 && next< sizeof(Message) )
************
JEDER Aufruf von uart1_getc muss untersucht werden.
JEDER!
KEINE AUSNAHME!
ALLE!
ALL OF THEM!
TUTTI COMPLETI
(auf französisch kann ichs nicht)
ALLE!
DU HAST EINEN AUFRUF VON UART_GETC? DANN SIEH DIR IM ERGEBNIS DIE
VERDAMMTEN FLAGS AN. WENN UART_NO_DATA GESETZT IST, DANN IST KEIN BYTE
VORHANDEN! Noch nicht. Aber was noch nicht ist, kann ja noch werden.
alle? JAAAAA, ALLE!
aber .... KEIN 'ABER'. ALLE! JEDEN EINZELNEN!
Das ist doch nicht so schwer! Das ist eine ganz einfache Regel.
(Und ich glaube wir hatten das vor ein paar Monaten schon mal)
@Lernender
Schau Dir noch mal das Beispiel aus dem Post von 20:09 an.
Das ist der komplette Code um die Daten einzulesen (ausser der
Initialisierung der Schnittstelle).
Also nicht unten drunter wieder Deinen falschen Code einbauen.
Und reg Karl Heinz nicht so auf !
:-)
Entschuldigt bitte
Ihr habts ja mehrfach gesagt nun gehts auch bei mir.
War immer auf die While abfrage fixiert das war falsch.
Trotzdem nochmal danke.
Lernender schrieb:> Leider geht das bei mir doch nicht so wies gedacht war.>
Du schreibst nicht was nicht geht bzw. was Du hier machen willst.
Was auffaellt:
Du hast keine Schleife mehr und liest nur noch ein Zeichen von der
Schnittstelle. Willst Du das?
Ansonsten fehlt ein while oder do-while. Poste doch mal Deinen
kompletten Code.
Das mit der do-while schleife blockiert ja dann das ganze Programm wenn
mal kein zeichen kimmt.
Es sollen vom Slave Zeichen gelesen werden bis die Slave-Adresse =55 als
Ende erkennung kommt.
Zeichen sehen wie folgt aus
zb. 889
zb.0010
Aber leider bekomme ich nur die ersten 3 zeichen.
1
uint8_tnext=0;
2
uint16_tc;
3
charMessage[70];
4
5
// Mainloop
6
while(1)
7
{
8
getdata();
9
10
DisplayText_s(41,35,Message);
11
12
}
13
}
14
15
16
uint8_tgetdata()
17
{
18
19
c=uart1_getc();
20
if((c&UART_FRAME_ERROR)||
21
(c&UART_OVERRUN_ERROR)||
22
(c&UART_BUFFER_OVERFLOW)){
23
// Fehlerbehandlung. Z.B. eine Led blinken lassen
24
}
25
elseif(c&UART_NO_DATA){
26
// kein Fehler. Aber es gibt (noch) kein Zeichen.
27
// Der Mc ist nunmal schneller als die Schnittstelle :-)
Lernender schrieb:> while (1)> {> getdata();>> DisplayText_s( 41, 35, Message);>> }> }
Wenn du dir Message laufend ausgeben lässt, dann musst du auch dafür
sorgen, dass Message nach jedem empfanegenen Zeichen wieder einen
gültigen String ergibt. Im Moment tust du das nicht!
> if ( c != 55 && next< sizeof(Message) )> {> TLED_ON();> Message[next++]=c;
Message[next] = '\0';
> }> else> {> Message[next] = '\0';> next= 0; // Zeichenzäühler auf null setzen> TLED_OFF();> }> }> }
Im übrigen: zeig alles!
Moment.
Deine Messages: sind die überhaupt Text?
Oder sind das einfach nur eine Abfolge von Bytes?
Zeig doch bitte auch mal die Protokollbeschreibung nach der du
programmierst. Das kommt mir ein wenig spanisch vor, dass jemand in
einem binären Protokoll die Dezimal-Konstante 55 verwenden würde. 55 ist
der ASCII COde für '7'. Und das wäre dann doch ein eher kurioses 'End Of
Message' Zeichen.
Ähm
> uart_putc(55); // device_ID ausgeben
Dir ist aber schon klar, dass 55 der ASCII Code für '7' ist?
d.h. sobald in deinen Daten
> sprintf(msg,"%02d",sens );> uart_puts(msg);> sprintf(msg,"%+03d,%1d", Vorkommastelle, Nachkommastelle);> uart_puts( msg);
irgendwo eine 7 vorkommt, dann wird der Empfänger das mit der von dir
angedachten Device-Id verwechseln!
Der Empfänger kriegst Bytes. Welche Bytes er als Codes für ASCII Zeichen
auffassen soll und welche Bytes direkt einen numerischen Wert
darstellen, kann er erst mal nicht unterscheiden. Das gibt dein
'Protokoll' bzw. die Implementierung beim Empfänger nicht her.
Lernender schrieb:> So habe die>> uart_putc(60); // device_ID ausgeben> device_ID vonn 55 auf 60 geändert trotzdem bekomme ich nur den ersten> wert!
Also ich verstehe es immer noch nicht. Was genau empfängst Du denn nun?
So wie ich das interpretiere, schickt Dir Dein Sensor einen String,
bestehend aus 8 Zeichen. Die ersten beiden stehen für die Sensornummer,
dann kommt das Vorzeichen des Messwerts, danach kommen zwei Zeichen, die
den ganzzahligen Anteil des Messwerts darstellen, dann ein Komma, dann
eine Nachkommastelle und dann noch ein Zeichen, dass die ID darstellt.
Mal ein Beispiel:
Der Sensor mit der Nummer "99" und der ID 60 sendet den Messwert "-9,8",
d.h. die Übertragung lautet:
1
"99-09,8<"
Was davon "bekommst" Du denn nun?
Was mir an Deinem Code sonst noch aufgefallen ist:
Lernender schrieb:> Wert[sensorNr] = messWert;> Wertkomma[sensorNr] = n;> if( sensorNr == 1 )> if( sensorNr == 2 )> if( sensorNr == 3 )
Der Variable "sensorNr", die Du hier mehrmals verwendest, wird nie ein
Wert zugewiesen.
> // ersten 2 stellen vorm komma mit Vorzeichen Speichern> int messWert = atoi( &Message[3] );
Der Messwert (das Vorzeichen) beginnt bei Index "2" nicht bei "3".
> int n= atoi( &Message[7]);
Gleicher Fehler hier: die Nachkommastelle befindet sich bei Index "6",
nicht "7".
Lernender schrieb:> So hier hab ich erstmal alles.
Alles ist das sicher nicht. Die includes fehlen z.B.
>> // Mainloop> while (1)> {> getdata();
//hier rufst Du getdata ohne Parameter auf. Laut Definition weiter unten
kommt hier ein Parameter hin. Nicht fein.
>>>> }> }>>> void getdata(uint8_t second)> {> uint16_t c;>
// da Du den parameter second nicht uebergibst wird der Code auch nicht
ausgefuehrt. Obwohl ich bezweifle das er sinnvoll ist...
> if (second== 1)> {_delay_ms(1000);> tempsend(T_mess,TEMPER_ADDR); // Komando zum Temperratur messen schicken> }
// Jetzt faengst Du an etwas sinnvolles zu machen
> c = uart1_getc();> if ( (c & UART_FRAME_ERROR) ||> (c & UART_OVERRUN_ERROR) ||> (c & UART_BUFFER_OVERFLOW) ) {> // Fehlerbehandlung. Z.B. eine Led blinken lassen> }> else if( c & UART_NO_DATA ) {> // kein Fehler. Aber es gibt (noch) kein Zeichen.> // Der Mc ist nunmal schneller als die Schnittstelle :-)> }> else> {> // kein Fehler und es liegt auch ein Zeichen vor.>> if ( c != 55 && next< sizeof(Message) )> {> TLED_ON();> Message[next++]=c;> }> else> {> Message[next] = '\0';> next= 0; // Zeichenzäühler auf null setzen> TLED_OFF();> }> }
// und hier hoerst Du mit der Sinnhaftigkeit auf.
// Nun verwendest Du den Buffer obwohl ja nichts oder hoechstend 1
Zeichen drin steht.
//Wieder mal: wo ist Deine while oder do-while Schleife?
// Ab hier machst Du nur noch Quatsch. Sorry.
> // ersten 2 stellen vorm komma mit Vorzeichen Speichern> int messWert = atoi( &Message[3] );> Wert[sensorNr] = messWert;> //nachkomma= n;> int n= atoi( &Message[7]);> Wertkomma[sensorNr] = n;>
...
>So habe die>> uart_putc(60); // device_ID ausgeben>device_ID vonn 55 auf 60 geändert trotzdem bekomme ich nur den ersten>wert!
Wie kommst Du nun auf die 60? Ich sage nicht das es falsch ist, aber
niemand ausser Dir weiss warum Du erst eine 55 und nun eine 60
verwendest.
Welches Protokoll soll das sein?
Ich will Dich wirklich nicht aergern oder beleidigen, aber Du solltest
definitv erst einmal ein C-Buch oder ein Tutorial durcharbeiten.
Mit Deinem Wissensstand wird das nix ...
So bekomme ich nur den ersten Wert vom Sensor angezeigt
getdata(second); wird doch in der While (1) schleife doch ständig
aufgerufen.
while (1)
{
getdata(second);
}
}
Mit der
do {
c = uart1_getc();
if ( (c & UART_FRAME_ERROR) ||
(c & UART_OVERRUN_ERROR) ||
(c & UART_BUFFER_OVERFLOW) ) {
// Fehlerbehandlung. Z.B. eine Led blinken lassen
}
else if( c & UART_NO_DATA ) {
// kein Fehler. Aber es gibt (noch) kein Zeichen.
// Der Mc ist nunmal schneller als die Schnittstelle :-)
}
else {
// kein Fehler und es liegt auch ein Zeichen vor.
Message[next++]=c;
}
} while (c!=55 && next<sizeof(Message));
wird ja das ganze Programm angehalten wenn kein zeichen kommt.