踮起脚摘苹果 发表于 2020-7-30 10:30:00

串口的校验位数据怎么算到的

/S00/1/ 0044 000000000000 0000 40 003C 3D 5C 21 1B 0100001F FFFF15 00000000 002D 0000 00 2C 2048
/S00/1/ 0044 000000000000 0000 40 003C 3D 5C 21 1B 0100001F FFFF14 00000000 002D 0000 00 2C 1F48

/S00/1/ 0044 000000000000 0000 40 003C 3C 5C 21 1B 0100011F FFFF13 000002F8 0001 0000 00 2C 155C
以上面数据为例,算一下末尾的 2048 1F48155C 为校验位,均为十六进制表示
在u8 USART1_Tranfer(void)中的checksum表示的是校验

/*十六进制转成ASCII码*/
u8 HexToAscill(u16 *hex, u8 *ascillbuf, u8 buflenth)
{
      u16 phex=*hex;
      u8 i=1;
      for(i=0;i<buflenth;i++)
      {
               ascillbuf = 0;
      }
      i = 1;
      if(&ascillbuf==NULL||phex==NULL)
      {
                for(i=0;i<buflenth;i++)
                {
                        if(ascillbuf==0)
                        {
                              ascillbuf = 0 + '0';
                        }
                }
                return 0;
      }

      while(phex!=0)
      {
                if((phex)%16<=9)
                {
                        ascillbuf = (phex)%16 + '0';
                }
                else
                {
                        ascillbuf = (phex)%16 + '7';//将10进制的phex转换成16进制取其个位+'7'ASSCII
                }
               
                phex = (phex)/16;
               
                i++;
               
                if(buflenth<i)
                {
                        break;
                }
      }
      for(i=0;i<buflenth;i++)
      {
                if(ascillbuf==0)
                {
                        ascillbuf = 0 + '0';
                }
      }
      return 1;
}



typedef union{
      u8 usart1_data;
      struct{
                u8head;// /S00/1/
                u8data_lentgh;/*from time data to checksum data*/
                u8datetime;
                u8random_number;
                u8fault_code;
                u8tds1_value;/*原水*/
                u8tds2_value;/*净水*/
                u8ntc0_temperature;/*不加热*/
                u8ntc1_temperature;/*热水*/
                u8ntc2_temperature;/*保温*/
                u8fixed_state;//固定状态
                u8percentage_of_filter_core;/*1 2 3*/
                u8total_running_time_of_water_pump;/*单位:秒*/               
///                u8PressurePumpCurrent;//增压泵电流,单位:mA               
                u8real_time_water_output;/*单位:毫升*/
                u8the_rest_of_the_day_bucket;
                u8fixtype;      
                u8end0;
      }s;
}__attribute__ ((aligned (1)))USART1_TRANSFER0_DATA_UNION;
extern volatileUSART1_TRANSFER0_DATA_UNION   Usart1_transf_data;

typedef union{
      u8 all;
      struct{
                u8 checksum;
                u8 end;/*\r\n*/
      }s;
}__attribute__ ((aligned (1)))USART1_DATA_END;
extern volatileUSART1_DATA_END               Usart1_data_end;

u8 USART1_Tranfer(void)
{
      char i=0,j=0,z=0;
    u8 datanum = 0;
    u8 head3 = 0;
    u8 head4 = 0;
    u16 checksum = 0;
      u16 *p=NULL;
      u8 req_dat_num=0,req_dat;
      u8 transdata={0};
      static u16 ticker=0;

   
      
      if(Transf_fifo!=0)
      {
               

                System_Data.usart1_tran_data_len = sizeof(USART1_TRANSFER0_DATA_UNION)+req_dat_num-7;
                //System_Data.usart1_tran_data_len = 77;//对应协议下发数据的指令字符串长度,除去Check Sum
                Usart1_transf_data.s.head = '/';
                Usart1_transf_data.s.head = 'S';
                Usart1_transf_data.s.head = head3;
                Usart1_transf_data.s.head = head4;
                Usart1_transf_data.s.head = '/';
                Usart1_transf_data.s.head = '1';
                Usart1_transf_data.s.head = '/';
                Usart1_transf_data.s.end0 = '2';
                Usart1_transf_data.s.end0 = 'C';

                Usart1_transf_data.s.ntc0_temperature = '2';
                Usart1_transf_data.s.ntc0_temperature = '2';

               

                for(i=0;i<sizeof(Usart1_transf_data.s.datetime);i++)
                {
                        if(Usart1_transf_data.s.datetime==0)
                        {
                              Usart1_transf_data.s.datetime += '0';//时间码
                        }
                }
                for(i=0;i<sizeof(Usart1_transf_data.s.random_number);i++)//回应随机数
                {
                        if(Usart1_transf_data.s.random_number==0)
                        {
                              Usart1_transf_data.s.random_number += '0';
                        }
                }               
                for(i=0;i<sizeof(Usart1_transf_data.s.fixed_state);i++)//固定状态
                {
                        Usart1_transf_data.s.fixed_state = System_Data.fixed_state;//固定状态的首字符为0
                }
                for(i=0;i<sizeof(Usart1_transf_data.s.fixed_state);i++)//fixed_state 为预留
                {
                        if(Usart1_transf_data.s.fixed_state==0)
                        {
                              Usart1_transf_data.s.fixed_state += '0';
                        }
                }
                for(i=0;i<sizeof(Usart1_transf_data.s.percentage_of_filter_core);i++)
                {
                        Usart1_transf_data.s.percentage_of_filter_core = 'F';//表示滤芯的首位值
                }
                if(Save_Data.s.machine_type==0||Save_Data.s.machine_type>9)
                {
                         Usart1_transf_data.s.percentage_of_filter_core = '0';//表示的是滤芯的第5位,为什么不是'1'呢?
                }
                else
                {
                        Usart1_transf_data.s.percentage_of_filter_core = Save_Data.s.machine_type + '0'; //不太明白
                }
               
                if(MachineWorkStatus==10)
                {
                        Usart1_transf_data.s.percentage_of_filter_core = 'A';//代表第六个元素的ASCII值
                }
                else
                {
                         Usart1_transf_data.s.percentage_of_filter_core = MachineWorkStatus + '0';//
                }
               
                HexToAscill((u16*)&(System_Data.pressure_pump_all_run_time), (u8*)Usart1_transf_data.s.total_running_time_of_water_pump, \
                                 sizeof(Usart1_transf_data.s.total_running_time_of_water_pump));
               
                //增加串口协议,用4位十六进制数表示增压泵电流,单位:mA
///                HexToAscill((u16*)&(System_Data.press_pump_current), (u8*)Usart1_transf_data.s.PressurePumpCurrent, \
///                                 sizeof(Usart1_transf_data.s.PressurePumpCurrent));
               
      
                HexToAscill((u16*)&(System_Data.real_time_water_output), (u8*)Usart1_transf_data.s.real_time_water_output, \
                                 sizeof(Usart1_transf_data.s.real_time_water_output));

                HexToAscill((u16*)&(System_Data.the_rest_of_the_day_bucket), (u8*)Usart1_transf_data.s.the_rest_of_the_day_bucket, \
                                 sizeof(Usart1_transf_data.s.the_rest_of_the_day_bucket));

                HexToAscill((u16*)&(System_Data.fixtype), (u8*)Usart1_transf_data.s.fixtype, \
                                 sizeof(Usart1_transf_data.s.fixtype));
               
                /*头部*/
                for(i=0;i<sizeof(USART1_TRANSFER0_DATA_UNION);i++)
                {
                        transdata = Usart1_transf_data.usart1_data;
                }
                /*中部 添加请求上位机的信息数据*/
                for(i=sizeof(USART1_TRANSFER0_DATA_UNION);i<sizeof(USART1_TRANSFER0_DATA_UNION)+req_dat_num;i++)
                {
                        transdata = req_dat;
                }
                p = (u16*)&transdata;
                for(i=0;i<(req_dat_num+sizeof(USART1_TRANSFER0_DATA_UNION)-7)/2;i++)
                {
                        checksum += p;
            // if(p>64) checksum -= 55;
            // else
            checksum -= 48;
            //if(i == 10) temp = checksum;
                }
      temp = p-48;//
                HexToAscill((u16*)&(checksum), (u8*)Usart1_data_end.s.checksum, \
                                 sizeof(Usart1_data_end.s.checksum));
               
                Usart1_data_end.s.end = '\r';
                Usart1_data_end.s.end = '\n';
               /*尾部*/
                for(i=sizeof(USART1_TRANSFER0_DATA_UNION)+req_dat_num;i<req_dat_num+sizeof(USART1_TRANSFER0_DATA_UNION)+sizeof(USART1_DATA_END);i++)
                {
                        transdata = Usart1_data_end.all;
                }
               
                datanum = sizeof(USART1_TRANSFER0_DATA_UNION)+sizeof(USART1_DATA_END)+req_dat_num;
                for(i=0;i<datanum;i++)
                {
                        USART_SendData(USART1,transdata);
                        
                        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}
                }
                for(i=0;i<FIFO_LENGTH-1;i++)
                {
                        Transf_fifo = Transf_fifo;
                }
                Transf_fifo = 0;
      }


      return 0;
}有知道最上面的那3行最末尾的4位校验和是怎么算的吗?

陌路夕颜 发表于 2020-8-3 18:02:49

你都有源码了直接在线仿真一下就明白了,先弄懂这个函数HexToAscill,然后再看199到208行的代码

mylovemcu 发表于 2020-8-4 09:03:03

通常校验说的有两种一种是串口本身的校验属于硬件校验就是奇偶校验另一种就是你用的这种协议中自定义的
奇偶校验是不需要考虑的自定义的校验需要程序实现的
具体实现的方式有很多
你这种属于和校验就是把所有的数据都加一起得出一个16位数据存在最后的字节中但你这个每两个和加完以后又减去一个固定的值这就是防止破解的如果单纯的和校验是很容易破解的但是减去一个固定值破解起来就困难了许多减去的这个固定值是在接收两端都设计好就能增加破解难度
其他的破解还有CRC或者利用公式等等都是为了数据的安全和可靠性

踮起脚摘苹果 发表于 2020-8-4 09:51:35

陌路夕颜 发表于 2020-8-3 18:02
你都有源码了直接在线仿真一下就明白了,先弄懂这个函数HexToAscill,然后再看199到208行的代码 ...

是的,已经算到了p = (u16*)&transdata;
                for(i=0;i<(req_dat_num+sizeof(USART1_TRANSFER0_DATA_UNION)-7)/2;i++)//字符和十六进制是2:1的关系,一个字符/一个ASCII 1个字节,可表示2位十六进制数
                {
                        checksum += p;
            // if(p>64) checksum -= 55;
            // else
            checksum -= 48;
            //if(i == 10) temp = checksum;
                }

u8类型用(u16*)的指针,一次性取16bit   00 46 00 ...然后HexToAscii是先转后一个字节的ASCII,再转前一个字节的ASCII (0x3030-30H)+(0x3634-30H)+...+ (n=48)总共是48个ASCII码参与校验

踮起脚摘苹果 发表于 2020-8-4 10:42:34

mylovemcu 发表于 2020-8-4 09:03
通常校验说的有两种一种是串口本身的校验属于硬件校验就是奇偶校验另一种就是你用的这种协议中自 ...

正解

butterflyspring 发表于 2020-8-12 10:44:51

mylovemcu 发表于 2020-8-4 09:03
通常校验说的有两种一种是串口本身的校验属于硬件校验就是奇偶校验另一种就是你用的这种协议中自 ...

全面,准确,正解 :)
页: [1]
查看完整版本: 串口的校验位数据怎么算到的