Hallo Leute, ich hab ein Kleines Problem und zwar wird in meiner
Schleife warscheinlich nicht richtig umgewandelt und dann nicht richtig
gerechnet.
Hier erstmal der Code:
1
voidUSART_readline(char*daten)
2
{
3
charNextChar;
4
unsignedcharDataCntTmp=0;
5
uint16_tNextInt;
6
uint16_tChecksumme=0;
7
while(1)
8
{
9
NextChar=USART_getchar();
10
NextInt=atoi(NextChar);
11
12
13
14
if(NextInt==Checksumme)/* Hier steht die checksumme am Ende */
15
{
16
/* Ende des Strings erreicht,
17
also Schleife verlassen */
18
USART_Transmit(NextChar);
19
20
return;
21
22
}
23
else/* Normales Zeichen, anhängen an die Zeichenkette */
24
{
25
daten[DataCntTmp]=NextChar;
26
DataCntTmp++;
27
Checksumme=Checksumme+NextInt;
28
USART_Transmit(Checksumme);
29
}
30
}
31
32
}
also die Schleife soll chars empfangen und in ein array speichern,
leider läuft die Schleife gleich nach dem ersten String durch und wird
beendet obwohl nach dem ersten Durchgang NextInt != Checksumme sein
sollte.
Denn wenn ich ihm Hex 45 schicke dann sollte NextInt auf keinen Fall den
Wert 0 haben weil ihr über atoi(nextchar) ja der Wert 45 zugewiesen wird
und somit die Schleife nicht durch return verlassen werden.
aber das tut sie offensichtlich. Da nach dem ersten Zeichen die
Programmausführung auserhalb der Schleife weiter geht.
Irgendwas haut mit der atoi Funktion nicht hin
NextInt ist nämlich danach immernoch 00 obwohl es 45 sein müsste oder
auf jeden fall ungleich 0.
Ich hoffe ihr habt mein Problem verstanden und könnt mir helfen
a) Lies nochmal ganz genau nach, was *atoi()* macht (und warum du da
eine Warnung vom compiler bekommst)
b) Du bist dir ganz sicher, das die Checksumme einmal in der Nachricht
vorkommt? (besonders weil du da uint16 mit uint8 vergleichst)
c) Finde noch den Unterschied zwischen 'char', 'char *' und 'char[]'
heraus.
rtfcbuch, Jörg
zu a)
Prototyp: int atoi ( const char *ntpr);
Wandelt den Anfangsteil einer Zeichenfolge, auf die nptr zeigt, in eine
int- Zahl um.
zu b)
sind doch beides uint16_t, aber werds in int ändern.
Ja die Checksumme sind einfach alle bytes aufsummiert und die kommt
irgendwann in der Zeichenkete vor und ist das Endzeichen. Die Zeichen
die empfangen werden sind alles hex-Ziffern.
zu c)
char ist ein Variablen typ, char[] ist ein array und char * ist ein
Pointer oder?
Wo liegt jetzt mein Denkfehler ich seh ihn nämlich nicht.
Christian Hohmann schrieb:
> zu a)> Prototyp: int atoi ( const char *ntpr);> Wandelt den Anfangsteil einer Zeichenfolge, auf die nptr zeigt, in eine> int- Zahl um.
Exakt.
Und jetzt schaun wir mal was du machst
1
NextInt=atoi(NextChar);
Welchen Datentyp hat NextChar?
In deiner Beschreibung sprichst du von einer Zeichenfolge. Ist NextChar
eine Zeichenfolge? Kann es aufgrund seines Datentyps überhaupt eine
Zeichenfolge sein?
PS: Das ganze Protokoll sieht seltsam aus.
Da werden solange Zeichen empfangen, bis sich mit dem nächsten Byte die
Checksumme ergibt, die als erstes übertragen wurde. Irgendwie kommt mir
das schon sehr restriktiv vor. Da stelle ich mir das Generieren eines
beliebigen Datensatzes schon teuflisch schwer vor. Wenn sich zufällig in
den Daten das richtige byte an der richtigen Stelle befindet, dann kann
es durchaus vorkommen, dass die Checksumme schon vor Ende des
Datensatzes bereits erreicht ist und die Leseroutine bricht vorzeitig
ab.
Christian Hohmann schrieb:
> ist vom typ char, also brauch ich da irgendwie einen pointer oder wie> sieht das aus?
atoi will einen String haben!
Du hast keinen String. Du hast ein einzelnes Zeichen!
Ergo: atoi ist das falsche Werkzeug.
http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F
(Und das ist nur ein klitzekleiner Auszug aus dem was man wissen muss um
in C Stringverarbeitung zu machen. Der ganze auch noch wichtige Rest
findet sich in jedem noch so grindigen C-Buch)
nicht ganz richtig.
Mit Checksumme = Checksumme + NextInt; wird ja immer das folgende Byte
zur Checksumme hinzuaddiert.
So sieht eine Anweisung aus die der MC empfangen und (vorerst) speichern
soll:
4D4105530001000200E9
E9 ist die Checksumme alle Bytes aufaddiert...
Christian Hohmann schrieb:
> nicht ganz richtig.> Mit Checksumme = Checksumme + NextInt; wird ja immer das folgende Byte> zur Checksumme hinzuaddiert.> So sieht eine Anweisung aus die der MC empfangen und (vorerst) speichern> soll:> 4D4105530001000200E9>> E9 ist die Checksumme alle Bytes aufaddiert...
Ah. ok.
Aber das macht es auch nicht besser. Eher sogar schlimmer.
wie würdest du es machen wenn ich fragen darf?
An den Zeichenketten die der MC empfängt kann ich nix ändern die kommen
von einer Steuerung. aber ich brauch diese hexwerte in einem Array
sodass ich auf jedes einzelne zugreifen kann.
Das ist natürlich jetzt nicht alles in der Funktion aber ich will mich
herantasten und und wenn das eine funktioniert will ich zum nächsten
gehen. deswegen auch der schlechte code...
Christian Hohmann schrieb:
> An den Zeichenketten die der MC empfängt kann ich nix ändern die kommen> von einer Steuerung.
Aber diese Steuerung wird ja wohl eine Protokollbeschreibung haben. Ich
will einfach nicht glauben, dass die Protokollbeschreibung lautet: Lies
solange dahin, bis die Summe der Bytes mit dem empfangenen Byte
übereinstimmt.
Wenn dem tatsächlich so ist, sollte man dem der die Steuerung gemacht
hat mal mit dem nassen Fetzen aufsuchen.
Angenommen die zu übertragenden Daten wären:
4D4105930001000200
Du rechnest du jetzt noch eine schöne Checksumme aus und hängst sie
hinten drann.
Aber dein Lesecode
4D ist noch ok. Checksumme bisher 4D
41 auch noch ok. Checksumme bisher 8E
05 auch noch ok. Checksumme bisher 93
93 oops. Das ist identisch zur bisherigen Checksumme, woraufhin deine
Leseroutine den Datensatz als beendet erklärt :-)
Das Protokoll der Steuerung ist nicht offen aber ich hab dir noch etwas
unterschlagen, hab ich glatt vergessen.
Das dritte byte gibt die länge der nachfolgenden Zeichen ohne Checksumme
an also bei
4D4105530001000200E9
4D41 Steurkommandos
05 anzahl der nachfolgenden Zeichen ohne checksumme
5300010002 Nutzzeichen
00E9 Checksumme( tut mir leid sind 2 bytes)+ich hoffe jetzt wirds besser
das ist jetzt aber alles
wurde alles durch probieren mit terminalprogramm und nem Delphi programm
rausgefunden, ( da bin ich mehr firm drin)
Christian Hohmann schrieb:
> Das Protokoll der Steuerung ist nicht offen aber ich hab dir noch etwas> unterschlagen, hab ich glatt vergessen.> Das dritte byte gibt die länge der nachfolgenden Zeichen ohne Checksumme> an
Ah, Na also.
Dann mach deine Schleife über diese Anzahl und benutze die Checksumme
danach um zu kontrollieren, ob die Übertragung richtig war.
> 00E9 Checksumme( tut mir leid sind 2 bytes)+ich hoffe jetzt wirds besser> das ist jetzt aber alles
Und als Zahl kriegst du die so
Checksumme = Byte1 * 256 + Byte2;
und benutze unbedingt unsigned char (oder uint8_t) für die Bytes.
Punkt 1:
wenn du es mit Bytes zu tun hast, dann ist unsigned char (oder
uint8_t) der Datentyp der Wahl
Punkt 2:
In C ist ein char (bzw. signed char bzw. unsigned char) im Grunde
auch nur ein Integer, mit dem man genauso rechnen kann, wie mit
allem anderen. Das ist anders als in den meisten anderen
Programmiersprachen, bei denen ein Character ausschliesslich
zur Speicherung und Verarbeitung von tatsächlichen ASCII-Zeichen
reserviert ist.
Hast du also 2 Bytes
uint8_t Byte1 = 0xDE;
uint8_t Byte2 = 0x89;
dann kannst du die beiden zu einem uint16_t zusammensetzen:
uint16_t Wert = Byte1 * 256 + Byte2;
oder was gleichwertig ist:
uint16_t Wert = ( Byte1 << 8 ) | Byte2;
(Beides wird vom Compiler höchst wahrscheinlich gleich übersetzt, da
alles unsigned ist und die Multiplikation eine Operation mit einer 2-er
Potenz darstellt).
Wert enthält dann 0xDE89
hm sieht eigentlich gut aus aber das mit der Checksumme stimmt irgendwie
nicht, er gibt jedenfalls immer false zurück wenn ich ihm
4D4105530001000200E9 schicke...
Wenn ich mir die Checksumme ausgeben lasse:
Christian Hohmann schrieb:
> hm sieht eigentlich gut aus aber das mit der Checksumme stimmt irgendwie> nicht, er gibt jedenfalls immer false zurück wenn ich ihm> 4D4105530001000200E9 schicke...>> Wenn ich mir die Checksumme ausgeben lasse:>
> steht Hex 56 drin.
Ich sagte doch, dass du noch kontrollieren musst, welche Bytes in die
Checksummenberechnung einfliessen müssen.
Wenn du den Code ansiehst, habe ich nur die Datenbytes in die Berechnung
mit eingehen lassen:
4D 41 05 53 00 01 00 02 00 E9
0x53 + 0x00 + 0x01 + 0x00 + 0x02 ergibt 0x56
Aber anscheinend werden KommandoBytes und Länge auch mit eingerechnet,
da
0x4D + 0x41 + 0x05 + 0x53 + 0x00 + 0x01 + 0x00 + 0x02 = 0xE9
das richtige Ergebnis ergibt.
Diese Änderung im Code wirst du doch wohl noch alleine hinkriegen.
Und ich hab ein weiteres Problem:
Also hab ein GrafikDisplay am Controller hängen was mir die Daten
anzeigt die die eigentliche Steuerung an den Controller sendet.
Bei trockenübungen mit Kommandos vom PC klappt auch alles aber wenn ich
den Controller an die Steuerung anschließe dann rattern die Daten so
schnell rüber das ich nichts auf dem Display erkennen kann da ständig
neue Sachen angezeigt werden, also die Daten kommen zu schnell rüber
weil der MC die Quittierungsstrings so shcnell sendet, ich bräuchte
jetzt eine Verzögerung für die Quittierungsstrings, von sagen wir mal 1
Sekunde.
Wie kann man das am schnellesten und einfachsten machen?
Habe das mit den Timern gelesen nur habe ich damit noch nix gemacht,
oder kann man auch immer ne schleife zählen lassen bis 100000 damit er
beschäftigt ist? Wär aber bestimmt quick and dirty
Hier mal noch mein Code zum Antwortstring und Anzeige auf Display falls
gewünscht:
1
//Sonst hier weiter: Antwortstring generieren und senden
2
3
//Kommando für Temperaturwerte schicken (nur einmal)
Dein Hauptproblem ist die Unsitte, den Schirm ständig löschen zu müssen.
Das ist erstens langsam und führt zweitens bei schnellen Datenänderungen
zu flackern bzw. dazu, dass man überhaupt nichts mehr lesen kann.
Entscheide dich wo am Schirm Daten dargestellt werden und schreibe
dorthin ohne jedesmal den Schirm komplett zu löschen. Daten sollen sich
überschreiben und nicht vorher gelöscht werden müssen. Bei schnellen
Datenänderungen kann man dann zwar ebenfalls nicht viel lesen, aber
sobald sich der erhaltene Wert stabilisiert hat man dann ein wunderbar
stehendes Bild, bei dem sich der angezeigte Wert ab und zu mal ohne
Zeitverzug ändert.
Aber wenn du eine Quick&Dirty Warterei brauchst ....
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Warteschleifen_.28delay.h.29
#include <util/delay.h>
...
_delay_ms( 1000 ); // 1000 Millisekunden = 1 Sekunde
Jetzt hab ich mal ne Frage nachdem mein Controller nicht mit der
Steuerung reden will.
Kann ich über die isp Schnittstelle sehen was auf der Seriellen
Schnittstelle geschrieben wird?
Hab ein mysmart usb programmer, wär nicht schlecht weil ich ned weis ob
die Steuerung was zurück sendet, weil mit dem Pc funktionierts aber mit
dem controller nicht...
Wenn man das direkt anzeigen lassen könnte wär das nicht schlecht
Christian Hohmann schrieb:
> Jetzt hab ich mal ne Frage nachdem mein Controller nicht mit der> Steuerung reden will.> Kann ich über die isp Schnittstelle sehen was auf der Seriellen> Schnittstelle geschrieben wird?> Hab ein mysmart usb programmer, wär nicht schlecht weil ich ned weis ob> die Steuerung was zurück sendet, weil mit dem Pc funktionierts aber mit> dem controller nicht...> Wenn man das direkt anzeigen lassen könnte wär das nicht schlecht
Du musst deine Teststrategien noch verfeinern.
Bei so etwas benutzt man den PC zum Testen von beidem
* zuerst kommt die Steuerung an den PC und mit einem Terminalprogramm
'spielt' man ein wenig mit der Steuerung und sieht sich an, was sie
so sendet und ob/wie sie auf Kommandos reagiert
* dann kommt der µC an den PC und mit sieht wieder im Terminalprogramm
nach, wie der µC reagiert wenn man ihm die Steuerung über das
Terminalprogramm vorgaukelt und ob er die richtigen Kommandos
sendet
und erst dann verbindet man Steuerung und µC und da beide Komponenten
unabhängig voneinander ihre Funktionstüchtigkeit gezeigt haben und in
ihrem Verhalten bekannt sind und aufeinander abgestimmt wurden wird die
Kommunikation auf Anhieb klappen. Zudem hat man mit der 'erst mal beide
an den PC' Methode auch verifiziert, ob die physikalischen Parameter
sowohl der Steuerung als auch des µC stimmen (Baudrate, Handshake,
sonstige Einstellungen)
Hab ich ja eigentlich alles gemacht, ich arbeite mit nem usb zu seriell
wandler und dem Programm hterm. Habe das Gefühl das wenn ich den PC an
der Steuerung habe nur die Hälfte des Strings angezeigt wird und beim
nächsten string der Rest des Vorherigen, das ist mir mit dem Lappi
eigentlich erstmal egal da ich eh den gleichen Antwortstring zurück
sende, aber der MC weis das ja ned und er kommt ´mit seiner Checksumme
durcheinander und macht ned weiter.
Wie ist das eigentlich mit dem Empfangspuffer des MC macht der wenn noch
daten im empfangspuffer liegen trotzdem mit seinem Programm weiter oder
muss ich sicherstellen das dieser leer ist bevor er weiter im Programm
geht?
Ich musss das nochmal mit der Steuerung mit nem pc mit richtiger
serieller Schnittstelle probieren, wie da die Daten nun kommen.
So ich habe jetzt mal meinen pc mit dran gehängt um zu sehen ob die
Kommunikation zwischen den beiden klappt, aber ich hab jetzt ein Problem
wie ich die erste antwort der steuerung verarbeiten soll:
Also folgendes:
ICh schicke initialisierungskommando:
52 61 01 01 00 B5 (Ra)
darauf antowrtet die Steurung aber mit gleich 2 Befehlen hinterienander:
52 61 01 01 00 B5 4D 41 05 53 00 01 00 02 00 E9 (Ra...) und (MA...)
jetzt schreibt die mir natürlich den eingangsbuffer vom controller voll
mit dem ersten Befehl den ich eigenlich ignorieren kann und nur am 2ten
interessiert bin , später werden auch nur immer ein Befehl gesendet aber
bei der initialiserung ist eben dieser blöde befehl davor gesetzt.
Wie kann ich dem Controller am einfachsten sagen das er die ersten 5
Zeichen ignorieren soll, das er das aber nur einmal tun soll?
Hier nochmal mein leider wieder etwas wild gewordener Quellcode: