程序小白
认证:优质创作者
作者动态
单片机应用与驱动开发之路:这时的你只需要扣动扳机。
1星期前
串口通信CRC校验大小端之分
3星期前
小小调度器——开局default,优雅总藏于细节之中
04-02 09:23
小小调度器——调度器核心的纯C实现
04-01 14:09
小小调度器——原来C代码还能这么写,原作者没少挨打吧!
03-27 15:42

串口通信CRC校验大小端之分

      从没想过串口通信CRC校验不通过是因为大小端引起的,真是好痛的领悟。。。假设你是玩单片机的,又和安卓屏或者其它类型的屏幕通信,那要注意了。对方的通信协议数据可能是这样定义的:

  data.D1_SN = Mcont.chipId;
  data.D2_warning = Mcont.warning;      
  data.D3_fliter_time = Mcont.save_data.filter_time;
  data.D4_ecell_time  = Mcont.save_data.vtimer_all;
  data.D5_mcu1_ver = MCU1_SVER;
  data.D6_muc2_ver = Mcont.slave.D16_ver;
  data.D7_main_state = Mcont.status;
  data.D8_work_state = Mcont.point;

      data.Dx:内存有可能是一个字节,也有可能是两个以上的字节,假设是两个字节,数据只发送一个uint16_t类型的数据,数值为0x1234,那么这个数据通过串口实际的输出是什么?

串口发送: 第一个字节     第二个字节

                     0x12                0x34(大端)

                     0x34                0x12(小端)

      实际痛苦的经历是这样的,接收数据和发送方确认是对的,但是CRC校验无论如何都通不过,经过一番仔细操作后发现,CRC校验高低字节顺序是不对的,于是呼呼呼。。。问发送端要了他的CRC校验代码(实锤了):

//***CRC校验 CRC16-MODBUS类型  eof为帧尾0表示没有  web尾0x23    endian 大小端模式 0大端 1小端**********************************************
void addCrc16_MODBUS(uint8_t *data1, uint16_t len,uint8_t eof,uint8_t endian)
{
    uint16_t i, pos, crc = 0xFFFF;

    for (pos = 0; pos < len; pos++)
    {
        if ((signed char)data1[pos] < 0)
        {
            crc ^= (int)((signed char)data1[pos]) + 256;
        }
        else
            crc ^= (int)((signed char)data1[pos]);
        for (i = 8; i != 0; i--)
        {
            if ((crc & 0x0001) != 0)
            {
                crc >>= 1;
                crc ^= 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    if(endian)
    {
    data1[len] = crc;
    data1[len + 1] = crc >> 8;
    }
    else{
    data1[len] = crc >> 8;
    data1[len + 1] = crc;
    }

    if(eof)
    data1[len + 2] = eof; //帧尾
}

第一次见CRC还有带大小端转换的功能,长见识了:

我们接触大部分单片机都是小端模式,但是也有大端模式例如经典的51单片机。

如何写一段代码判断设备是大端还是小端模式:

    #include <stdio.h>
    int main(){
        union{
            int n;
            char ch;
        } data;
        data.n = 0x00000001;  //也可以直接写作 data.n = 1;
        if(data.ch == 1){
            printf("Little-endian\n");
        }else{
            printf("Big-endian\n");
        }
        return 0;
    }

在电脑上的运行结果是:

Little-endian

实际大小端模式在内存中的区别如下:

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 3
收藏 6
关注 120
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧