Guten Tag, ich möchte Messwerte (Integer) vom PC an der uC über USB (FT232 im Einsatz) senden. Zur Zeit benutze ich den USART. Ich zerlege auf dem PC mein Integer in die unterschiedlichen Ziffern und sende im festen Datenformat: z.B. Integer 123 -> Char "0" "1" "2" "3" Auf dem uC interpretiere ich die "Zahl" als: atoi(0)* 1000 + atoi(1) * 100 + atoi(2) * 10 + 1* atoi(3) = 123 Nun kann ich sie weiterverarbeiten. Ziemlich umständlich. Hat wer einen einfachen Alternativansatz ?Setze es in C auf dem ATMega16 um. Vielen Dank
du kannst es dcoh einfach binär senden. Integer 123 wird dann als "0x00 0x7b" also 2 zeichen gesendet. Du musst nur ein Protokoll definieren damit du den anfang und das ende der zahlen erkennst.
Ich finde Klartext prima. Lässt sich auch einfach debuggen. Ich verstehe auch gerade nicht, welches Problem Du beseitigen möchtest. Gruß Jobst
Peter II schrieb: > du kannst es dcoh einfach binär senden. Jaja. Das ist die einfachste und zugleich dümmste Methode, denn sie enthält keinerlei Mittel, um die zwei beteiligten Rechner zu synchronisieren. Stell dir vor, jemand will Zahlen >255 senden. Was dann? Hoffen, daß nie was dazwischenkommt? Nee, irgendeine Art Protokoll ist schon nötig. Aber was soll das? "atoi(0)* 1000 + atoi(1) * 100 + atoi(2) * 10 + 1* atoi(3) = 123" Ich verstehe nicht den tieferen Sinn dieses langen Schriebses. Wahrscheinlich würde ich das sinngemäß etwa so machen und die Zahlen mit nem Komma voneinander separieren: var L : longint; C : Char; L:= 0; C:= #0; repeat if CharAvailable(MyComport) then begin C:= GetTheChar(MyComport); if C in ['0'..'9'] then L:= L*10+(C-'0'); until (C=',') or (MyState=HaveNoLustMehr); DoSomething(L); GoToBed; end. W.S.
W.S. schrieb: >> du kannst es dcoh einfach binär senden. > Jaja. Das ist die einfachste und zugleich dümmste Methode, denn sie > enthält keinerlei Mittel, um die zwei beteiligten Rechner zu > synchronisieren. klar doch - aus dem Grund verwendet PPP oder Ehternet auch Klartext. Text ist das dümmste was man machen kann, dann dann muss man auf beiden seiten wandeln denn für ein computer ist das so nicht verständlich. Warum sollen sich 2 Computer in der Sprache der Menschen unterhalten?
Du kannst es auch per Hand umrechnen indem du von der Zahl eine 59 glaub ich abziehst, müsst mal gucken welchen hex Wert eine 0 hat. Da sparste dir zumindest das atoi. Ingo
ATMega16_Einsteiger schrieb: > z.B. Integer 123 -> Char "0" "1" "2" "3" > > Auf dem uC interpretiere ich die "Zahl" als: > > atoi(0)* 1000 + atoi(1) * 100 + atoi(2) * 10 + 1* atoi(3) = 123 Und warum bastelst Du nicht aus den vier Zeichen einen String, den Du dann atoi vorwirfst? atoi("0123") = 123 ...
ATMega16_Einsteiger schrieb: > Auf dem uC interpretiere ich die "Zahl" als: > > atoi(0)* 1000 + atoi(1) * 100 + atoi(2) * 10 + 1* atoi(3) = 123 > > Nun kann ich sie weiterverarbeiten. Ziemlich umständlich. Du kannst auch einfach atoi("0123") machen, dann kannst du dir das Zusammenbasteln von Hand sparen.
Peter II schrieb: > klar doch - aus dem Grund verwendet PPP oder Ehternet auch Klartext. Die meisten Protokolle verwenden in der Tat Klartext. Peter II schrieb: > Text ist das dümmste was man machen kann, dann dann muss man auf beiden > seiten wandeln denn für ein computer ist das so nicht verständlich. ASCII-Text ist in der Tat eine der schlausten Arten, Daten zu übertragen, oft sogar zu speichern. "Der" Computer "weiß" keineswegs, ob ihm Zahlen in 8/16/32/... Bit Breite, mit oder ohne Vorzeichen, als binäre Ganzzahl oder als Fließkomma, in Little oder Big Endian vorgelegt werden. > Warum sollen sich 2 Computer in der Sprache der Menschen unterhalten? Man kann natürlich auch ASN.1 nehmen. In den meisten Fällen ist das aber schlicht Overkill.
Dauergast schrieb: > Die meisten Protokolle verwenden in der Tat Klartext. nur keine bei denen aus auf geschwindigkeit und effizienz ankommt. Auch würde ich mich mit "meisten" sehr zurück halten, ich kenn kaum Protokolle außerhalb von http (inc. mail) wo etwas im klartext gemacht wird. ( PPP, XMODEM, ETHERNET, IP, TCP, X25, ISDN, TDS (sql-server) usw. ) > ASCII-Text ist in der Tat eine der schlausten Arten, Daten zu > übertragen, oft sogar zu speichern. "Der" Computer "weiß" keineswegs, ob > ihm Zahlen in 8/16/32/... Bit Breite, mit oder ohne Vorzeichen, als > binäre Ganzzahl oder als Fließkomma, in Little oder Big Endian vorgelegt > werden. warum sollte eine ineffizienzte (mehr Platz und mehr CPU-Resourcen) lösung sinnvoll sein? Weil ebend der computer nicht weiss was für daten kommen definiert man ja ein Protokoll in diesem ist festgelgt welche Daten wie übertragen werden. > Man kann natürlich auch ASN.1 nehmen. In den meisten Fällen ist das aber > schlicht Overkill. ASN.1 ist wirklich etwas übertrieben, ich würde es aber einem XML parser vorziehen wenn es schnell und resourcen schonden werden soll.
Peter II schrieb: > warum sollte eine ineffizienzte (mehr Platz und mehr CPU-Resourcen) > lösung sinnvoll sein? Wesentlich ineffizienter ist es nur, wenn Du auf beiden Seiten zufällig dieselbe Wortbreite, Endianität und dasselbe Alignment hast. Aber das ist eher selten, und noch seltener für die Zukunft vorhersehbar.
Dauergast schrieb: > Wesentlich ineffizienter ist es nur, wenn Du auf beiden Seiten zufällig > dieselbe Wortbreite, Endianität und dasselbe Alignment hast. Aber das > ist eher selten, und noch seltener für die Zukunft vorhersehbar. gut dann ist es nur noch 5mal so effizent und nicht mehr 10mal effizent.
ATMega16_Einsteiger schrieb: > z.B. Integer 123 -> Char "0" "1" "2" "3" > > Auf dem uC interpretiere ich die "Zahl" als: > > atoi(0)* 1000 + atoi(1) * 100 + atoi(2) * 10 + 1* atoi(3) = 123 "1" ist ein String. Das Zeichen wäre '1'. Eine String ist ein Nullterminiertes char-Array. atoi erwartet als Argument ein Nullterminiertes char-Array und kein einzelnes Teichen. Das klappt also nicht so, wie du es probierst. Ansonsten kannst du von den empfangenen Zeichen einfach '0' abziehen.
1 | char text[] = "0123"; |
2 | zahl = atoi(text); |
3 | //oder
|
4 | zahl = (text[0] -'0') * 1000 + (text[1] -'0') * 100 + (text[2] -'0') * 10 +(text[3] -'0'); |
5 | //oder
|
6 | for(i=0, zahl=0;text[i];i++) |
7 | zahl = zahl * 10 + (text[i] -'0'); |
Wobei die letzten beiden keine Rücksicht auf Buchstaben oder Sonderzeichen nehmen :-(
Peter II schrieb: > Dauergast schrieb: >> Die meisten Protokolle verwenden in der Tat Klartext. > > nur keine bei denen aus auf geschwindigkeit und effizienz ankommt. Auf Applikationsebene sind im Internet so gut wie alle gängigen Standard-Protokolle textbasiert. Manche neueren Protokolle wie Jabber benutzen sogar XML. >> ASCII-Text ist in der Tat eine der schlausten Arten, Daten zu >> übertragen, oft sogar zu speichern. "Der" Computer "weiß" keineswegs, ob >> ihm Zahlen in 8/16/32/... Bit Breite, mit oder ohne Vorzeichen, als >> binäre Ganzzahl oder als Fließkomma, in Little oder Big Endian vorgelegt >> werden. > > warum sollte eine ineffizienzte (mehr Platz und mehr CPU-Resourcen) > lösung sinnvoll sein? Es ist programmiertechnisch die einfachste. Außerdem läßt es sich viel einfacher debuggen. Wenn der Overhead nicht besonders stört, ist es sinnvoller, diese Vorteile zu nutzen.
Uc: Sprintf(string,"%d",Zahl); send-uart-s(string); Pc: get_String(String); atoi(String); Is zwar Ucseitig nicht Ressourcensparend aba am einfachsten! Bessere Variante wäre mit Bitshift den integer in 2 chars umwandeln und pcseitg wieder zusammensetzen : char = integer <<8; usw.. ( pseudocode-> siehe tutorial Bitoperationen)
Rolf Magnus schrieb: > Auf Applikationsebene sind im Internet so gut wie alle gängigen > Standard-Protokolle textbasiert. Manche neueren Protokolle wie Jabber > benutzen sogar XML. richtig aber hier geht es um ein übertragungsrpotokoll auf der Seriellen Leitung und übertragungsprotkolle sind auf den unteren schichten sind meist keine Text Protokolle. > Uc: Sprintf(string,"%d",Zahl); send-uart-s(string); > Pc: get_String(String); atoi(String); schon die verwendung von Sprintf macht es noch schlimmer, es gibt auch itoa! Hast du mal auf einen µC die anzahl der Take für diese beiden zeilen dir angeschaut? Wir reden hier mindestens vom ein paar 100. uint16_t zahl; uc: send( Zahl, sizeof(Zahl) ); pc: Read( Zahl, sizeof(Zahl) ); bei bedarf kann man noch ein LittleEdian/Bigendian swap einbauen. > Es ist programmiertechnisch die einfachste. Außerdem läßt es sich viel > einfacher debuggen. Wenn der Overhead nicht besonders stört, ist es > sinnvoller, diese Vorteile zu nutzen. ist schon erstaunlich das das ganze Wissen um die Verarbeitung von Binären daten in den letzen Jahren verloren gegangen ist. Vor 10Jahren hatte die Programmieren damit keine Probleme. Aber heute muss ja alles auf XML gemacht werden, sonst wüssten die CPUs gar nicht mehr was sie machen sollen.
Peter II schrieb: > ist schon erstaunlich das das ganze Wissen um die Verarbeitung von > Binären daten in den letzen Jahren verloren gegangen ist. Da gab es auch noch Methoden wie z.B. das "sixeln" um unabhängig von 7,e,1 oder 8,n,1 auf der seriellen übertragen zu können. Gruß Anja
Peter II schrieb: > richtig aber hier geht es um ein übertragungsrpotokoll auf der Seriellen > Leitung und übertragungsprotkolle sind auf den unteren schichten sind > meist keine Text Protokolle. Auf RS232 hat man meistens keine unteren Schichten. Wozu auch? >> Uc: Sprintf(string,"%d",Zahl); send-uart-s(string); >> Pc: get_String(String); atoi(String); > schon die verwendung von Sprintf macht es noch schlimmer, es gibt auch > itoa! Was macht es schlimmer? Es braucht natürlich mehr Ressourcen, aber wenn man die zur Verfügung hat, wird dadurch gar nichts schlimmer. Wie es immer so schön heißt: Man bekommt von Atmel kein Geld für nicht benutzten Speicher zurück. Und mit sprintf hab ich den Vorteil, daß ich auch gleich eine komplette Zeile auf einmal erzeugen kann, statt die aus lauter Einzelwerten mühevoll zusammenzubasteln. Wenn die Ressourcen nicht verfügbar sind, braucht man natürlich eine andere Lösung. Aber programmiertechnisch ist sprintf die einfachste Möglichkeit. > Hast du mal auf einen µC die anzahl der Take für diese beiden zeilen dir > angeschaut? Wir reden hier mindestens vom ein paar 100. Und? Unmittelbar danach werden wahrscheinlich Tausende von Taktzyklen in einer Schleife verbraten, die nix andres tut, als darauf zu warten, daß der nächste Programmzyklus losgeht. > uint16_t zahl; > > uc: send( Zahl, sizeof(Zahl) ); > pc: Read( Zahl, sizeof(Zahl) ); > > > bei bedarf kann man noch ein LittleEdian/Bigendian swap einbauen. Um sowas braucht man sich bei Text nicht kümmern. Auch nicht um ein Protokoll, das es schafft, nach Unterbrechungen wieder den Anfang des nächsten Datenpakets zu finden. Das ergibt sich bei zeilenweiser Textübertragung quasi von selbst. >> Es ist programmiertechnisch die einfachste. Außerdem läßt es sich viel >> einfacher debuggen. Wenn der Overhead nicht besonders stört, ist es >> sinnvoller, diese Vorteile zu nutzen. > ist schon erstaunlich das das ganze Wissen um die Verarbeitung von > Binären daten in den letzen Jahren verloren gegangen ist. Vor 10Jahren > hatte die Programmieren damit keine Probleme. Ich schrieb nicht, daß es ein Problem ist, sondern nur, daß es umständlicher ist. > Aber heute muss ja alles auf XML gemacht werden, sonst wüssten die CPUs > gar nicht mehr was sie machen sollen. XML finde ich dann auch etwas übertrieben. Wenn man sich Sachen wie xmlrpc anschaut, hat man das Gefühl, daß es die Erfinder darauf angelegt haben, den Overhead so groß wie nur irgend möglich zu machen.
Hallo, Danke für die Antworten. Habe mein Programm angehängt. Ich übergebe vom PC aus: 0100001234 => Pin 0 Status 1 (High) Verzögerung 1234 us etc. Also: 01000012341100001234210000123431000012344100001234 für einen Vorgang. (Ich habe am Controller 5 Kanäle nach Außen geführt. Mein Problem: Die Pins werden richtig geschaltet. Die Verzögerung in us stimmt nicht (mit Oszilloskop überprüft). Trage ich in die Delayfunktion einen festen Wert selber ein ..also nicht über die Variable Time[n], dann stimmen die Zeiten. Hat wer Anregungen wo ich mit der Fehlersuche beginnen kann. Ich suche schon etwas länger. Habe mir alles Ausgeben lassen, die Zeichen werden scheinbar richtig übertragen. Danke
Hi, ich habe es zwar noch nicht selbst versucht, aber laut dem AVR-GCC-Tutorial kann man dort keine Variablen einsetzen.
ATMega16_Einsteiger schrieb: > z.B. Integer 123 -> Char "0" "1" "2" "3" > > Auf dem uC interpretiere ich die "Zahl" als: > > atoi(0)* 1000 + atoi(1) * 100 + atoi(2) * 10 + 1* atoi(3) = 123 > > Nun kann ich sie weiterverarbeiten. Ziemlich umständlich. Hat wer einen > einfachen Alternativansatz ?Setze es in C auf dem ATMega16 um. Marcus hat ja schon darauf hingewiesen, dass du bei _delay_us keine Variable verwenden kannst. Das heißt: Du kannst schon. Nur stimmen die Zeiten nicht. Zu deiner ursprünglichen Frage. Wenn du das hier
1 | ....
|
2 | for (j = k;j<k+8;j++) |
3 | {
|
4 | Time[j] = usart_receive_char(); |
5 | };
|
6 | ....
|
7 | |
8 | weiterer Code mit vielen Hilfsvariablen und einer |
9 | Wahnsinnsmultiplikation, die letzten Endes dafür sorgt, dass |
10 | in Time_us_ die richtige Zahl entsteht. |
so schreibst
1 | ....
|
2 | Time_us_[i] = 0; |
3 | |
4 | for (j = 0; j < 8; j++) // das k braucht kein Mensch da drinnen |
5 | {
|
6 | Time_us_[i] = 10 * Time_us_[i] + usart_receive_char() - '0'; |
7 | }
|
8 | ....
|
hast du an dieser Stelle bereits alles beisammen: Die Umrechnung von Zeichen in einen echten Integer (das was bei dir die Funktion char_to_int gemacht hat) UND die Aufsummierung zur vollständigen Zahl (das was deine Multiplikationen mit den Hilfsvariablen gemacht haben). OK, nicht ganz. Deine Hilfsfunktion char_to_int hat noch Fehlerprüfung gemacht. So gesehen wäre der 100% Ersatz
1 | int char_to_int( char c ) |
2 | {
|
3 | if( c >= '0' && c <= '9' ) |
4 | return c - '0'; |
5 | |
6 | return 0; |
7 | }
|
8 | ...
|
9 | ...
|
10 | |
11 | Time_us_[i] = 0; |
12 | |
13 | for (j = 0; j < 8; j++) // das k braucht kein Mensch da drinnen |
14 | {
|
15 | Time_us_[i] = 10 * Time_us_[i] + char_to_int( usart_receive_char() ); |
16 | }
|
17 | ....
|
Einsteiger_ATMega16 schrieb: > Mein Problem: > Die Pins werden richtig geschaltet. Die Verzögerung in us stimmt nicht > (mit Oszilloskop überprüft). Trage ich in die Delayfunktion einen festen > Wert selber ein ..also nicht über die Variable Time[n], dann stimmen die > Zeiten. Du hast also weder die Doku der avr-libc, noch die Warnung des Compilers gelesen. Solltest du mal tun.
Ich habe keine Warnung erhalten. Die avr-libc habe ich echt nicht gelesen. Jedenfalls bin ich bei der Delay Funktion nicht drüber gestolpert. Sorry. Ich habe die Funktion: void pause(int zeit) { int i; for (i = 0;i<zeit;i++) { _delay_us(1);} }; nun genommen, bekomme aber immernoch falsche Zeiten. Hat wer eine Idee? Danke
Einsteiger_ATMega16 schrieb: > Ich habe die Funktion: > > void pause(int zeit) > { > int i; > for (i = 0;i<zeit;i++) > { _delay_us(1);} > }; > > nun genommen, bekomme aber immernoch falsche Zeiten. Hat wer eine Idee? jetzt läufst du in ein anderes Problem rein. In einem Programm ist es ja nicht so, dass nur ein _delay_us Zeit verbraucht, sondern auch der Rest des Programmes. Solange die _delay_us Zeiten groß gegenüber dem Rest sind, spielt das keine allzugroße Rolle. Hier aber landest du mit 1us schon in Zeitbereichen, in denen die komplette Schleifensteuerung zeitlich gesehen in einer ähnlichen Größenordnung liegt, bzw. je nach Taktfrequenz sogar darüber. d.h dein _delay_us(1) verbraucht schon 1 µs. Aber die for-Schleife drumherum verbraucht nochmal oder gar noch mehr Zeit als diese 1us. Und deshalb stimmen dann die Zeiten nicht. Ist wie beim Fliegen. Der Flug München-Berlin dauert 50 Minuten. Kann man deswegen sagen, du kannst in 50 Minuten in Berlin sein? Nein, kann man nicht. Denn du musst erst mal zu Flughafen fahren, musst dort eine gewisse Zeit vorher dort sein. Musst das Checkin-Procedere über dich ergehen lassen, etc. etc. Summa summarum brauchst du daher für einen 50 Minuten Flug reale 4 Stunden. Vielliecht verstehst du jetzt schön langsam, warum hier bei Wartezeiten ala _delay_ms bzw _delay_us alle die Hände über dem Kopf zusammenschlagen. Wenn die Zeiten exakt sein sollen, bzw. länger sein sollen, ist das alles nicht zu gebrauchen. _delay_xx sieht zwar auf den ersten Blick super einfach aus, ist es aber nicht. Wenn die tatsächliche Wartezeit auch etwas länger sein darf UND vor allen Dingen, wenn es nicht zu lange ist (Millisekunden Bereich), kann man es benutzen. Aber für alles andere ist das nicht brauchbar. Da führt kein Weg an der Benutzung eines Timers vorbei.
Peter der Großartige schrieb: > Text ist das dümmste was man machen kann, dann dann muss man auf beiden > seiten wandeln Du schriebest Unsinn. Versuch doch bitte mal, zuerst zu denken und dann zu schreiben. Und unser Einsteiger_ATMega16 schrieb: > Ich übergebe vom PC aus: > > 0100001234 => Pin 0 Status 1 (High) Verzögerung 1234 us etc. > > Also: > 01000012341100001234210000123431000012344100001234 > > für einen Vorgang. Oh du Einsteiger, mach es lieber anders. Das was du da gepostet hast, ist schlecht, weil es einfach extrem unflexibel ist. Du bist auf der "Denkschiene" der festen Blöcke, wo alle Positionen festgelegt und starr sind und alle Kommandos nicht atomar, sondern zusammengesetzt sind. Jaja, man kann zwar so leben, aber besser ist es, nur atomare Kommandos zu benutzen. Das sind welche, die nur 1 Information transportieren. Ich geb dir mal ein Beispiel. Nehmen wir an, du brauchst im Moment 3 verschiedene Kommandos: - Pin High setzen - Pin Low setzen - Verzögerungszeit vereinbaren Dann wäre es ne günstige Sache, zuerst nen numerischen Wert (also ne Zahl) zu schicken und dann das atomare Kommando, also eines, das wirklich nur 1 Sache bewerkstelligt. Beispiel: (V setzt die Verzögerungszeit, L setzt auf Low, H setzt auf High) 1234V1H2H34H99V4L Bedeutung: 1234V setzt die Verzögerungszeit auf 1234 us 1H setzt Pin 1 auf High 2H setzt Pin 2 auf High 34H setzt Pin 34 auf High 99V setzt die Verzögerungszeit auf 99 us 4L setzt Pin 4 auf Low Auf diese Weise kannst du formatfrei ohne führende Nullen senden, mit jedem Buchstaben synchronisiert sich der Kommandostrom selbst und du kannst jederzeit noch andere Kommandos erfinden, ohne daß es die bereits bestehenden Kommandos stört. Mit deinem o.g. Block 01000012341100001234210000123431000012344100001234 bist du längst nicht so flexibel. W.S.
W.S. schrieb: > Auf diese Weise kannst du formatfrei ohne führende Nullen senden, mit > jedem Buchstaben synchronisiert sich der Kommandostrom selbst und du > kannst jederzeit noch andere Kommandos erfinden, ohne daß es die bereits > bestehenden Kommandos stört. Und ... auch nicht ganz unwichtig: Du brauchst nur das Senden, was sich auch tatsächlich verändert. Womit dann auch dem 'Nicht Text' Argument mehr oder weniger der Boden unter den Füssen weggezogen wird.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.