Hallo zusammen, ich benutze avr studio und bei der funktion: uint16_t crc_ccitt_update (uint16_t crc, uint8_t data) { data ^= lo8 (crc); data ^= data << 4; return ((((uint16_t)data << 8) | hi8 (crc)) ^ (uint8_t)(data >> 4) ^ ((uint16_t)data << 3)); } und es kommt immer der fehler "implicit declaration of lo8 und hi8" Soweit ich weiss, müsste das ein include fehler sein!? Hab aber keine Ahnung in welcher sich die Funktion befindet. Vielleicht kann mir ja jemand helfen. Schon mal Danke!
Nein, es gibt kein "lo8" und "hi8" in C. Du hast versucht, Pseudo-Code aus einem Kommentar als richtigen C-Code 1:1 zu benutzen. Das geht so nicht. Man kann den Code natürlich umschreiben (ist ja weiter nichts als ein Maskieren und ggf. Schieben), habe ich auch schon (für den IAR, der diese Funktionen nicht in der Bibliothek hat) getan. Fragt sich, warum willst du das für avr-libc denn tun, da doch die entsprechende Funktion als recht effektive inline-asm-Implementierung zur Verfügung steht?
Hallo Jörg ich teste einfach ein wenig herum da mir die Funktion noch nicht das richtige zurückliefert. Ich muss einen Hex Code über UART senden und CRC anhängen. Es ist aber definitiv der richtige CRC Check (CCITT, ). In der Doku der anzusprechenden Karte hab ich ein Beispiel mit ausgerechnetem CRC. Hier ist das Beispiel. Vielleicht kannst du mir ja einen Tip geben warum es nicht funktioniert. Daten: 0x1A 0x00 0x0000 CRC: 0x84A2
"implicit declaration" bedeutet, daß der Compiler die betreffende Funktion nicht kennt. Also ist in keiner der von Dir eingebundenen Headerdateien "lo8" und "hi8" deklariert. Wenn sich das Programm aber von diesen Warnungen abgesehen übersetzen lässt und keine Linkerfehlermeldung à la "undefined symbol" ausgegeben wird, dann sind beide Funktionen in irgendeiner der von Dir verwendeten Libraries oder sogar in einem von Dir verwendeten Sourcefiles enthalten. Es fehlt also nur der Funktionsprototyp an der Stelle, an der die Warnung ausgegeben wird. Du solltest die Meldungen Deines Compilers verstehen lernen. Die sind nämlich hilfreich und sinnvoll.
Das hat sich schon geklärt, trotzdem danke! Sollte einen neuen Thread aufmachen. Hab jetzt ja das CRC Problem! Sry..
Was für 'ne Karte? Was für ein CRC-Polynom? Kommt hinzu, dass es die jeweils mit unterschiedlichen Startwerten und mit unterschiedlicher Bitorientierung gibt.
Das ist ne maxon Motorkarte DES 50/5. Hier mal ein Auszug zum crc aus dem Datenblatt. The 16-bit CRC checksum. The algorithm used is CRC_CCITT. The CRC calculation includes all bytes of the frame. The data bytes have to be calculated as a word. At first you have to shift in the high byte of the data word. This is the opposite way you transmit the data word. The 16-bit generator polynomial ‘x^16+x^12+x^5+1’ is used for the calculation. Order of crc calculation: ‘OpCode’, ‘len-1’, ‘data[0]’ high byte, ‘data[0]’ low byte, ... crc: Checksum of the frame. The low byte is transmitted first. Ich versteh das so das es CCITT und nicht xmodem ist. (hab ich aus der crc16.h gelesen) Meine main sieht so aus: ...main... usart_ini(); uint16_t crc[]={0xFFFF}; uint8_t data[]={0x1A,0x00,0x00,0x00}; uint16_t newcrc[]={0x00}; while(1) { newcrc[0]=_crc_ccitt_update(crc[0],*data); usart_puts(newcrc , sizeof(newcrc)); }; ich programmier einen atmega32 damit und schau es über den COM-Port an einem Terminal-Programm an.
Zu viele Unbekannte. Hast du mal 'n Link zum Datenblatt? Ich finde es bei maxonmotors.com nicht.
Das hier geht:
1 | #include <stdio.h> |
2 | #include <util/crc16.h> |
3 | #include <stdint.h> |
4 | |
5 | uint16_t crc = 0x0; |
6 | |
7 | uint8_t data[] = { 0x1a, 0, 0, 0, }; |
8 | |
9 | char b[20]; |
10 | |
11 | int
|
12 | main(void) |
13 | {
|
14 | uint8_t i; |
15 | |
16 | for (i = 0; i < 4; i++) { |
17 | crc = _crc_xmodem_update(crc, data[i]); |
18 | }
|
19 | |
20 | sprintf(b, "0x%0x", crc); |
21 | |
22 | return 0; |
23 | }
|
Was ist als wert bei dir herausgekommen?? bei mir kommt immer nur D5 oder so. Muss ja aber laut doc 0x730C herauskommen. Hab deinen code mal so eingebunden in mein programm. ich häng den code mal an. Vielleicht kannst ja was entdecken.
mach da mal ganz schnell > while(1) > { > uint16_t crc={0x0}; > > for (i=0;i<sizeof(data);i++){ > crc=_crc_xmodem_update(crc,data[i]); > } char buffer[20]; sprintf( buffer, "%x", crc ); usart_puts( buffer, strlen( buffer ) ); draus. Du kannst doch nicht einfach Binärzahlen über die Schnittstelle schicken und hoffen, dass da am anderen Ende irgendwas lesbares rauskommt.
ich versteh grad nicht genau was ich genau ändern soll? Aber ich bin für jede Hilfe dankbar. Außerdem meckert avr studio das er strlen und sprintf nicht kennt(implicit declaration).
Ich hab doch die Änderung hingeschrieben. Anstatt dem usart_send(crc); machst du char buffer[20]; sprintf( buffer, "%x", crc ); usart_puts( buffer, strlen( buffer ) ); Für strlen musst du noch #include <string.h> ganz am Anfang inkludieren. sprintf() ist glaub ich auch mit diesem Include abgedeckt. Wenn nicht, dann #include <stdio.h> Und dann empfehle ich dir noch ein C-Buch zu kaufen und durchzuarbeiten.
> Was ist als wert bei dir herausgekommen?
(gdb) targ rem :1212
Remote debugging using :1212
0x00000000 in __vectors ()
(gdb) c
Continuing.
Breakpoint 2, main () at foo.c:21
(gdb) p/x crc
$1 = 0x730c
@ karl Mein Problem ist dass ich nicht sicher weiß wass die Motorkarte haben möchte. Die Zeichen in Hex oder so wie du geschrieben hast in ASCII. Auf deine Weise macht die Karte mal bisher nichts. Kann aber auch an was anderem liegen. Wenn ich es ohne dein Tip mache kommt bis auf den crc der Rest in Hex richtig raus. danke für die erklärung.
Errm, aber du musst beide Bytes der CRC zur Motorsteuerung schicken! ``The low byte is transmitted first.'', also zuerst "crc & 0xff", danach "(crc >> 8) & 0xff".
Was verstehst du daran nicht? Deine UART-Routine gibt immer ein Byte auf einmal aus, aber die CRC ist eine CRC16, da musst du für die CRC also 2 Bytes ausgeben.
Also irgendwie will das nicht funtionieren. Ich krieg es irgendwie nicht hin aber trotzdem danke an alle. Werd noch dran verzweifeln. Wenn ich es richtig verstehe muss ich usart_send(data[0]); und dann auf das okay warten und dann den rest senden. Aber da passiert nichts.
Auf welches ,,OK'' willst du denn warten? Bist du dir sicher, dass du deren Doku überhaupt verstanden hast? Du musst data[0] bis data[N] über die serielle Schnittstelle schicken, anschließend low(CRC), danach high(CRC). Danach wird die Motorsteuerung dir irgendwas antworten, dass sie ebenfalls in einen solchen Frame verpackt. Darüber musst du erneut die CRC berechnen (über wie viele Bytes, das bekommst du indirekt aus Byte 2 der gesendeten Daten heraus), wenn du die CRC-Bytes mit in die CRC-Berechnung einschließt, dann sollte 0 herauskommen. Danach kannst dann daran gehen, die empfangene Antwort zu parsen. Zu allem Überfluss haben sie noch Schwierigkeiten mit der byte order. Für die CRC-Berechnung bewerten sie von ihren 16-Bit-Zahlen zuerst das high byte, dann das low byte, also in meinem Beispiel oben wäre data[] für das im Datenblatt genannte Antwortpaket dann:
1 | uint8_t data[] = { 0, 3, 0x10, 0x40, 0x40, 0x02, 0x00, 0xa1, 0x00, |
2 | 0x01, }; |
Für den Transport jedoch senden/empfangen sie bei den 16-Bit-Werten zuerst das low byte, dann das high byte, also von der 0x1040 wird zuerst die 0x40 und danach die 0x10 gesendet.
Das mit dem "ok" steht auf S.37 der Doku. Da lese ich heraus das ich auf ein "O" warten muss. Ansonsten hab ich das Problem mit der Byte order jetzt verstanden. Ob es funktioniert wird sich in den nächsten stunden zeigen. Danke Hätte ich auch erwähnen sollen das ich seit drei Tagen erst C Programmier?? Ich meine wegen dem Verständnis und der Kritik.
> Das mit dem "ok" steht auf S.37 der Doku. Ah ja, das hatte ich noch nicht gesehen. > Hätte ich auch erwähnen sollen das ich seit drei Tagen erst C > Programmier?? Ich meine wegen dem Verständnis und der Kritik. Naja, daher ja Karl Heinz' Hinweis auf ein gutes C-Buch. Aber Kommunikationsprotokolle muss man unabhängig von der benutzten Programmiersprache ebenso verstehen, wenn man sie implementieren will. Scheinst du ja aber mittlerweile zu tun. ;-)
> Aber Kommunikationsprotokolle muss man unabhängig von der benutzten > Programmiersprache ebenso verstehen, wenn man sie implementieren > will. Geb ich dir grundsätzlich recht. Nur finde ich es schon etwas heftig, den Einstieg in eine neue Programmiersprache (oder ist es überhaupt der Einstieg in die Programmierung) mit der Kommunikation 2-er Geräte zu beginnen. Das ist selbst für geübte Programmierer alles andere als ein Spaziergang, da die meisten normalen Debugging-Techniken da einfach nicht greifen und man oft auf Raten und Intuition und oft auch ein Quäntchen Glück angewiesen ist. Ich hätte mir zb. die CRC zuerst mal auf einem Terminal ausgeben lassen um zu sehen ob da überhaupt was richtiges rauskommt. Daher auch die sprintf() Geschichte weiter oben. Erst wenn ich 100% davon überzeugt bin, dass die Daten die ich zum Gerät senden will auch richtig sind, und ich die mal in einem ASCII-Dump gesehen habe, schicke ich sie mal binär zum Gerät. Da kann dann immer noch eine Menge schief gehen. Des weiteren würde ich mir für die Kommunikation zum Gerät eine Hintertür einbauen: Alles was zum Gerät gesendet wird, wird irgendwo anders in lesbarer Form mitprotokolliert. Ohne solche Dinge ist Kommunikation sehr oft einfach nur ein 'Stochern im Nebel'. Wenn man dann gleichzeitig auch noch den Umgang mit dem Stocher-Stock lernen muss, ....
Das mit dem Nebel trifft meine Situation grad ganz gut. Ich habe ein Terminal Programm (RealTerm) wo ich mir auch hex anzeigen lassen kann. Bei Methode 1 bekomme ich data() richtig angezeigt also beim Beispiel 1A 00 00 00. nur der crc wert dahinter stimmt nicht als hex. Wenn ich es wie Karl erläutert hat mache zeigt es mir den richtigen crc wert als ascii 730c an. Also ist das Problem momentan das ich wenn ich binär sende der CRC nicht stimmt. Woran kann das noch liegen? Von dem ganzen Byte geschiebe hab ich keine Ahnung.
> usart_send(data[0]); > > und dann auf das okay warten und dann > den rest senden. Aber da passiert nichts. Baudrate, Kommunikationsparameter, Kabel (kreuz / nicht kreuz) ? Versuch mal die Steuerung an einen normalen PC mit Hyperterminal oder einem anderen Terminalprogram. Drück mal 'Z' (soweit ich gesehen habe, ist der Code für 'Z' kein gültiges Kommando). Dann müsste die Steuerung mit einem 'F' (für Fehler) antworten. Tut sie das nicht, dann hast du ein Problem auf der RS232 Ebene. Also: Baudrate, 8N1, Kabel.
Was zeigt dein Kommunikationsprogramm denn an, wenn du statt der berechneten CRC die beiden Werte hartcodiert sendest?
Also Baudrate und 8n1 ist sicher richtig. rs232 auch richtig tx->Rx und umgekehrt. Bei Senden des crc ohne Berechnung kommt es gleich falsch raus. Also passt was noch nicht beim senden des crc. Hab den code noch mal angehängt. sieht jetzt halt ziemlich wild aus wegen dem auskommentieren.
Sorry, aber das ist immer noch alles ziemlich durcheinander. Du sendest wilden Datenmüll statt der berechneten CRC. Was du als CRC senden musst (hatte ich dir auch schon mal geschrieben) ist:
1 | usart_send(crc & 0xff); |
2 | usart_send((crc >> 8) & 0xff); |
Die CRC ist eine 16-Bit-Zahl, die du in zwei 8-bit-Übertragungen senden musst. Du darfst weder eins der beiden Bytes unterschlagen ("usart_send(crc);" und fertig), noch (wie jetzt) irgendwie versuchen, die 16-Bit-*Zahl* crc als 16-Bit-*Zeiger* auf einen (nicht vorhandenen) String zu deuten und den dann zu übertragen.
> Also Baudrate und 8n1 ist sicher richtig. rs232 auch richtig > tx->Rx und umgekehrt. OK. Gut. D.h. nachdem du das Kommando-Byte gesendet hast, antwortet die Steuerung mit 'O'. Hast du das kontrolliert? Wenn das nicht klappt, ist alles andere sinnlos. Wenns klappt: Gut. Das ist schon mal die halbe Miete. > Wie du das wieder geschaft hast, Dinge durch den Compiler zu bringen. Respekt! usart_puts() möchte einen Pointer auf einen String und du stopfst ihm einen uint16_t hinein. (Sorry, konte nicht wiederstehen. Eigentlich muesste dein Compiler da schon längst 'Feuer' schreien.) > Hast du den Vorschlag von Jörg schon mal probiert? > usart_send(data[0]); > > //back=usart_receive(); > //if(back==0){ Wenn schon, dann if( back == 'O' ) { denn die Steuerung schickt ja das Zeichen 'O' und keine 0 > usart_send( data[1] ); > usart_send( data[2] ); > usart_send( data[3] ); das sind die Datenbytes und jetzt jagst du noch eine dazupassende crc hinterher: usart_send( 0x0c ); usart_send( 0x73 ); Damit sollte sich mal was tun. Die crc wird zwar hardgecodet gesendet, aber was solls. Erst mal testen ob's überhaupt funkntioniert. Wenn das dann klappt, dann ersetzt du die Hardcore-Variante durch die berechnete crc anstatt usart_send( 0x0c ); usart_send( 0x73 ); kommt usart_send( crc & 0xFF ); usart_send( ( crc >> 8 ) & 0xFF ); das unden mit 0xFF ist eigentlich nicht notwendig, zeigt aber beim Aufrufer etwas deutlicher, dass da Bytes extrahiert werden.
Also das Senden klappt so. Ich hab auch getestet ob die Karte ein 'O'(hab ich im code übersehen) sendet, tut sie auch(0x4f). Ich habe ein anderen data zum Senden data[]={0x05,0x00,0x00,0x01}; Er schaltet die Karte auf Enable, wo ich am einfachsten sehe ob sie reagiert. Bis jetzt bleibt sie noch Disabled. Senden tu ich die Daten in dem Format data1[]={0x05,0x00,0x01,0x00}; Wenn ich das Sende und mithöre. Sagt sie 2 mal 'O'(0x4f). Das komische ist nur sie schaltet sich nicht an. hmmm. Laut doc sollte es ja nach 2 'O' gehen. @karl wenn ich es mit deinem Beispiel mache ist es dann so richtig zum empfangen der Antwort. 1. unsigned char buffer[20]; 2. for(i=0;i<20;i++){ 3. buffer=usart_receive(); 4. } und dann den buffer mit der puts ausgeben.
> Also das Senden klappt so. Ich hab auch getestet ob die Karte ein > 'O'(hab ich im code übersehen) sendet, tut sie auch(0x4f). Pfff. Mein Glückwunsch. > unsigned char buffer[20]; > for(i=0;i<20;i++){ > buffer=usart_receive(); > } buffer ist doch ein Array. Du must schon indizieren wo das naechste Zeichen abgelegt wird. for( i = 0; i < 20; i++ ) buffer[i] = usart_receive(); das ist der eine Punkt. Der nächste ist: > und dann den buffer mit der puts ausgeben. puts hält sich an die C-String Konventionen. Die besagen, dass die Character-Sequenz im Array mit einem '\0'-Zeichen abgeschlossen wird um anzuzeigen, dass der String hier aufhört (Das Array kann ja wesentlich größer sein, als der String der darin gespeichert ist). Also musst du im obigen noch ein '\0'-Zeichen an das letzte Zeichen anhängen. Damit wird die Array-Größe auch um 1 größer (weil ja ein zusaetzliches zeichen, eben der '\0' gebraucht wird) unsigned char buffer[21]; for( i = 0; i < 20; i++ ) { buffer[i] = usart_receive(); } buffer[20] = '\0'; So, jetzt hast du in buffer etwas, was du an String-verarbeitende Funktionen (wie zb. puts() Derivate) übergeben kannst.
Ach. Ich vergass. Dein usart_puts ist ja ein Krüppel, wer sich das ausgedacht hat, sollte sofort ... Ist mir schon mal aufgefallen, hab aber bisher nichts gesagt. > void usart_puts (uint16_t *s, unsigned n) { > // loop until *s != NULL > while (n--) { > usart_send(*s); > s++; > > } > } Also: Diese Funktion braucht keinen abschliessenden '\0'. Schadet nicht, ist aber unnötig. PS: Eine vernünftige Funktion würde so aussehen: void usart_puts( const char* s ) { unsigned char* pTmp = s; while( *pTmp ) usart_send( *pTmp++ ); } Damit braucht der Aufrufer nicht mehr länger abzählen, aus wievielen Zeichen der String denn besteht. Er hält sich einfach an die Konvention das da hinten ein '\0' Zeichen steht (ganz genauso wie alle anderen String- verarbeitenden Funktionen) und gut ists. Der einzige Fall, in dem die originale Funktion leichte Vorteile hat, liegt vor, wenn man aus einem größeren String einen Ausschnitt übertragen möchte. Kommt aber selten genug vor, so dass sich dieser Vorteil den Nachteil bei normaler String-Übertragung in keinster Weise rechtfertigt.
Die puts Funktion habe ich aus diesem Forum :-)!! Das der Motor anfängt zu laufen klappt immer noch nicht. Aber nach dem Senden von Enable kommen 2 O's. Müsste also klappen. Muss halt warscheinlich noch was zusätzliches senden. Mit der Drehzahl hab ich es schon versucht aber war nicht richtig. Muss ich mir alles noch mal genauer anschauen. Aber ich kann mich nur bei euch beiden nur bedanken!! Habt mir super geholfen! Vielen Dank!!
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.