Hi,
ich nutze zur Absicherung der Kommunikation zwischen Master und Slave
die _crc16_update() Funktion aus der AVR Libc:
http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html .
Aktuell bin ich noch dran, Slave und Master getrennt zu entwickeln. Ich
kopiere mir also einfach den vom Master erzeugen String inklusive
Checksumme (zum beispiel #DO,001,02,12345,01,01556,29610,63191\n), pack
das ganze in ein Terminalprogramm und schick es dem Slave. Das
funktioniert. Änder ich die Checksumme (der Letzte Abschnitt) oder die
Daten, akzeptiert der Slave die Übertragung nicht. Das funktioniert
also.
Der vollständigkeithalber, hier der Code vom Master:
Der Slave (UART_Data ist der komplette String, inkl \n)
1
//CRC Kontrolle:
2
uint8_t CRClen = strlen(UART_Data);
3
CRClen -= 6;
4
char cCRC[6];
5
strncpy(cCRC, UART_Data+CRClen, 5);
6
7
uint16_t CRC = 0xffff;
8
for (uint8_t i = 1; i < CRClen-1; i++) //CRC berechnen
9
{
10
CRC = _crc16_update(CRC, UART_Data[i]);
11
}
12
if (atol(cCRC) == CRC)
13
ReturnVal = 1; //CRC Ok
14
else
15
ReturnVal = 4; //CRC Falsch
Da aber auch der PC mit dem Master kommunizieren soll und es mir vor
allem das Debuging einfacher macht, wollte ich mir einen kleinen
CRC-Calculator am PC bauen. Allerdings komm ich weder mit den Online-CRC
Rechnern auf das Ergebnis wie der Controller, noch mit einem kleinen
Visual C# Programm, das auf dem Code aus der <util/crc16.h> beruht.
Die CRC16 mit dem Programm von unten lautet: 20274.
PC-Programm:
Weiß jemand Rat? Was überseh ich? Oder ein Prinzipfehler?
Controller: AVR-Familie (Mega32L auf dem Testboard, später dann 328p-au)
Compiler: GCC 4.7.2 (AVR Studio 6.1)
PC: .NET4 (Visual Studio C# 2010 Express)
In C würde der gezeigte Code auf jeden Fall in die Hose gehen. Ob auch
in C# hängt von diversen Fragen ab, wie z.B.:
Wie groß ist char in C#?
Welche Signedness hat char in C#?
Hat C# die selben Promotion-Rules wie C?
Ich kenne die Antworten nicht, denn ich kann kein C#.
Ich vermute aber mal, dass es in C# wegen der gleichen (oder ähnlicher)
Gründe in die Hose geht.
Mache a unsigned.
"a" unsigned. Wenn es für die 16 Bit Operation "crc ^= a;" erweitert
wird ("crc" hat ja 16bit), wird oben 0 ergänzt.
Bei Deiner
1
2
static UInt16 crc16_update(UInt16 crc, char a)
3
{
4
UInt16 i;
5
6
crc ^= a;
7
for (i = 0; i < 8; ++i)
8
{
9
if ((crc & 1) == 1)
10
crc = (UInt16)((crc >> 1) ^ 0xA001);
11
else
12
crc = (UInt16)(crc >> 1);
13
}
14
15
return crc;
16
}
ist nicht ganz klar, ob "a" signed oder unsigned ist und wie viele Bit
es hat. Wenn man 8 Bit signed annimmt, dann würde die Erweiterung auf 16
Bit nicht nur 0 sondern bei Werten mit gesetztem höchsten Bit 0xff oben
ergänzen. Damit würde sich dann das abweichende Ergebnis erklären.
Stefan Ernst schrieb:> In C würde der gezeigte Code auf jeden Fall in die Hose gehen.
Warum?
> Wie groß ist char in C#?
16-Bit Unsigned
> Mache a unsigned.
Auch mit byte (8-Bit Unsigned) kommt das selbe raus.
Ich hab mir das wohl zu einfach vorgestellt mit Copy&Paste.
Was mich aber wundert, warum in den Online-CRC-Rechnern auch überall
meist vollständig andere Ergebnisse bei raus kommen?
Zum beispiel:
http://www.zorc.breitbandkatze.de/crc.html
Martin K. schrieb:> Ich hab mir das wohl zu einfach vorgestellt mit Copy&Paste.
Mit der Erkenntnis stehst du nicht alleine.
Cx sind Programmiersprachen, bei denen man genau wissen muss, was man
tut, insbesondere wenn das ganze Konstrukt hinterher auch noch auf
verschiedenen Systemen ohne Änderungen funktionieren soll.
Martin K. schrieb:> Stefan Ernst schrieb:>> In C würde der gezeigte Code auf jeden Fall in die Hose gehen.> Warum?
Das "auf jeden Fall" war etwas übertrieben. Wenn man dem Compiler sagt,
dass char per Default unsigned zu sein hat, dann nicht (wäre dann aber
immer noch sehr schlechter Stil). Was ansonsten passiert, hat Achim doch
schon erklärt.
Martin K. schrieb:>> Wie groß ist char in C#?> 16-Bit Unsigned
Aha. Und welchen Datentyp hat string[x]? Und was steht in diesem char
dann konkret drin? Sind das wirklich ASCII-Codes?
Hast du überhaupt mal ganz grundsätzlich überprüft, ob auch in beiden
Fällen wirklich identische Inputdaten an die CRC-Routinen verfüttert
werden? Und damit meine ich jetzt nicht, was du irgendwo als Text
eingibst, sondern, was als binäre Daten in der CRC-Routine ankommt.
Martin K. schrieb:> Was mich aber wundert, warum in den Online-CRC-Rechnern auch überall> meist vollständig andere Ergebnisse bei raus kommen?
Was sollen wir dazu sagen? Hier wissen wir ja noch weniger darüber, was
genau du da eingestellt/eingegeben hast.
Stefan Ernst schrieb:> Was sollen wir dazu sagen? Hier wissen wir ja noch weniger darüber, was> genau du da eingestellt/eingegeben hast.
CRC-CCITT
CRC order 16
CRC polynom A001
Initial value ffff (direct)
Final XOR value 0
Result: 0x6133
Ich hab noch ein wenig mit Visual C# gespielt, komm aber auf kein
Ergebnis. Hier und da gibt es Routinen im Netz für CRC16-CCITT, auch mit
dem Polynom A001. Mit einer Variante war ich seltsamerweise immer exakt
91 UNTER den vom µC berechneten werden. Sehr frustrierend grade. Vllt.
seh ich auch den Wald vor lauter bäumen nicht mehr.
Martin K. schrieb:> Stefan Ernst schrieb:>> Was sollen wir dazu sagen? Hier wissen wir ja noch weniger darüber, was>> genau du da eingestellt/eingegeben hast.>> CRC-CCITT> CRC order 16> CRC polynom A001> Initial value ffff (direct)> Final XOR value 0>> Result: 0x6133
Und was hast du als Inputdaten eingegeben, und was als Ergebnis
erwartet?
Martin K. schrieb:> Sorry, natürlich den String von oben:>> #DO,001,02,12345,01,01556,29610>> Erwartete Checksumme: 63191 (0xF6D7)
Warum das '#'? Deine eigenen Routinen ignorieren doch das erste Zeichen,
der Online-Rechner aber natürlich nicht.
Der Online-Rechner scheint in die andere Richtung zu shiften. Wenn du
das Polynom umdrehst (A001->8005) und die beiden Reverse-Häkchen setzt,
kommt bei "DO,001,02,12345,01,01556,29610" genau das raus:
> Erwartete Checksumme: 63191 (0xF6D7)
Stefan Ernst schrieb:> Warum das '#'? Deine eigenen Routinen ignorieren doch das erste Zeichen,> der Online-Rechner aber natürlich nicht.
Oh verdammt, das ist mir gar nicht aufgefallen... ich stell mich ins Eck
und schäm mich! ;)
Vielen Dank für deine Hilfe. Denke damit komm ich erst mal weiter :)
Hallo,
Ich hatte ähnliche Probleme mit der (bzw. einer) CCITT-CRC und wollte
übereinstimmende Ergebnisse zwischen srec_cat, der avr-libc und der
Breitbandkatze erhalten.
Hab es erst kürzlich hinbekommen und die screenshots (breitbandkatze),
den Example-Code und das script-file f. srec_cat in ein File
zusammengepackt (am Ende des Threads). Wie erwähnt: ist halt eine CCITT
und nicht CRC16.
Vielleicht hilft es mal jemandem weiter:
TitelBeitrag "CRC generierung mittels srec_cat"
Gruß,
Andreas
>> ist nicht ganz klar, ob "a" signed oder unsigned ist und wie viele Bit> es hat. Wenn man 8 Bit signed annimmt, dann würde die Erweiterung auf 16
Wenn man ein Byte benötigt, würde ich den Datentype "byte" empfehlen.
Der ist 8 bit unsigned.
Ich hab mich noch mal dran gesetzt, aber kam nicht weiter. Mit diversen
Routinen aus dem Netz hab ich es versucht, aber ich kam nicht auf mein
Ergebnis.
Nach mehreren Stunden ohne weiter zu kommen hab ich das jetzt erst mal
aufgegeben und bin grad an einer anderen Stelle vom Projekt.
Vielleicht hab ich beim nächsten Versuch ja eine Eingebung :)