Forum: Compiler & IDEs implicit declaration lo8


von sebastian (Gast)


Lesenswert?

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!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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?

von sebastian (Gast)


Lesenswert?

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

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

"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.

von sebastian (Gast)


Lesenswert?

Das hat sich schon geklärt, trotzdem danke!
Sollte einen neuen Thread aufmachen. Hab jetzt ja das CRC Problem!
Sry..

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von sebastian (Gast)


Lesenswert?

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 &#8216;x^16+x^12+x^5+1&#8217; is used for
the calculation.

Order of crc calculation: &#8216;OpCode&#8217;, &#8216;len-1&#8217;,
&#8216;data[0]&#8217; high  byte, &#8216;data[0]&#8217; 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.

von sebastian (Gast)


Lesenswert?

Im Moment bekomme ich 5C 4F

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Zu viele Unbekannte.  Hast du mal 'n Link zum Datenblatt?  Ich
finde es bei maxonmotors.com nicht.

von sebastian (Gast)


Lesenswert?


von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
}

von sebastian (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Karl heinz B. (kbucheg)


Lesenswert?

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.

von sebastian (Gast)


Lesenswert?

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).

von Karl heinz B. (kbucheg)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> 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

von sebastian (Gast)


Lesenswert?

@ 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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Die Motorsteuerung will es binär haben.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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".

von sebastian (Gast)


Lesenswert?

tut mir leid aber das versteh ich grad nicht ganz wie du das meinst.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von sebastian (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von sebastian (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> 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. ;-)

von Karl heinz B. (kbucheg)


Lesenswert?

> 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, ....

von sebastian (Gast)


Lesenswert?

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.

von Karl heinz B. (kbucheg)


Lesenswert?

> 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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Was zeigt dein Kommunikationsprogramm denn an, wenn du statt der
berechneten CRC die beiden Werte hartcodiert sendest?

von sebastian (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Karl heinz B. (kbucheg)


Lesenswert?

> 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.

von sebastian (Gast)


Lesenswert?

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.

von Karl heinz B. (kbucheg)


Lesenswert?

> 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.

von Karl heinz B. (kbucheg)


Lesenswert?

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.

von sebastian (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.