Arduino至覆盆子crc32 ch

2024-10-03 23:24:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图通过我的ARDUINO(C++)的串行USB接口发送消息给Raspberry Pi(Python)。在

在Arduino端,我定义了一个结构,然后将其复制到char[]中。结构的最后一部分包含我要使用CRC32计算的校验和。我把这个结构复制到一个临时的char数组-4个字节以除去校验和字段。然后使用临时数组计算校验和,并将结果添加到结构中。然后将结构复制到byteMsg中,byteMsg通过串行连接发送。在

在raspberry端,我做相反的操作,我接收bytestring并计算消息-4字节的校验和。然后解压bytestring并比较接收到的和计算出的校验和,但不幸的是,这失败了。在

为了调试,我比较了python和arduino上的crc32检查字符串“Hello World”,它们生成了相同的校验和,所以库似乎没有问题。覆盆子还能够很好地解码其余的消息,因此将数据解包到变量中似乎也没问题。在

任何帮助都将不胜感激。在

Python代码:

   def unpackMessage(self, message):
        """ Processes a received byte string from the arduino """

        # Unpack the received message into struct
        (messageID, acknowledgeID, module, commandType,
         data, recvChecksum) = struct.unpack('<LLBBLL', message)

        # Calculate the checksum of the recv message minus the last 4
        # bytes that contain the sent checksum
        calcChecksum = crc32(message[:-4])
        if recvChecksum == calcChecksum:
            print "Checksum checks out"

Aruino crc32库取自http://excamera.com/sphinx/article-crc.html

crc32.h型

^{pr2}$

Arduino主草图

struct message_t {
    unsigned long messageID;
    unsigned long acknowledgeID;
    byte module;
    byte commandType;
    unsigned long data;
    unsigned long checksum;
};

void sendMessage(message_t &msg)
{
    // Set the messageID
    msg.messageID = 10;
    msg.checksum = 0;

    // Copy the message minus the checksum into a char*
    // Then perform the checksum on the message and copy
    // the full msg into byteMsg
    char byteMsgForCrc32[sizeof(msg)-4];
    memcpy(byteMsgForCrc32, &msg, sizeof(msg)-4);
    msg.checksum = crc_string(byteMsgForCrc32);

    char byteMsg[sizeof(msg)];
    memcpy(byteMsg, &msg, sizeof(msg));

    Serial.write(byteMsg, sizeof(byteMsg));

void loop() {
    message_t msg;
    msg.module = 0x31;
    msg.commandType = 0x64;
    msg.acknowledgeID = 0;
    msg.data = 10;

    sendMessage(msg);

谨致问候, 泰森


Tags: the消息messagemsgbyte结构校验long
2条回答

您犯了网络/串行/插入通信层的经典结构错误。结构具有隐藏的填充,以便将成员与适当的内存边界对齐。这不能保证在不同的计算机上是相同的,更不用说不同的CPU/微控制器了。在

以这个结构为例:

struct Byte_Int
{
     int x;
     char y;
     int z;
}

现在在一个基本的32位x86 CPU上,有一个4字节的内存边界。这意味着根据变量的类型,变量被对齐到4字节、2字节或者根本不对齐。这个例子在内存中是这样的:intx在字节0,1,2,3上,chary y在字节4上,intz在字节8,9,10,11上。为什么不使用第二行的三个字节呢?因为这样的话,内存控制器必须进行两次回迁才能得到一个数字!控制器一次只能读取一行。因此,结构(和所有其他类型的数据)都有隐藏的填充,以便使变量在内存中对齐。这个示例结构的sizeof()应该是12,而不是9!在

现在,这和你的问题有什么关系?您正在memcpy()将一个结构直接放入缓冲区,包括填充。另一端的计算机不知道这个填充,并且误解了数据。您需要一个序列化函数,该函数一次一个地将结构的成员传递到缓冲区中,这样一来,您将丢失填充并最终得到如下结果: [0,1,2,3:整数x][4:字符y][5,6,7,8:int z]。所有这些都是一个很长的bytearray/string,可以使用Serial()安全地发送。当然,在另一端,您必须将此字符串解析为可理解的数据。只要提供正确的格式字符串,Python的unpack()就可以为您完成这项工作。在

最后,Arduino上的int是16位长的。在pc上一般4!所以要小心地组装解包格式字符串。在

我传递给crc_string函数的char数组包含'\0'个字符。crc_字符串在数组中迭代,直到找到一个'\0',在本例中不应该出现这种情况,因为我使用char数组作为通过串行连接发送的字节流。在

我更改了crc_string函数,以数组大小作为参数,并使用该值遍历数组。这就解决了这个问题。在

这是新函数

unsigned long crc_string(char *s, size_t arraySize) 
{ 
  unsigned long crc = ~0L; 
  for (int i=0; i < arraySize; i++) { 
    crc = crc_update(crc, s[i]); 
  } 
  crc = ~crc; 
  return crc; 
}

相关问题 更多 >