java CRC16校验,原版C++,改编成java

本文详细介绍了CRC16校验码的计算原理及应用,包括使用多种编程语言实现CRC16校验码的计算过程。适用于需要了解或实现CRC16校验的开发者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
/*
 * crc校验,输入一个数组,返回一个数组,返回的数组比原数组
 * 多了两个字节,也就是两个校验码,低字节在前,高字节在后.
 */
public class CRC16 {
 public static int[] crc(int[] data){
  int[] temdata=new int[data.length+2];
  //unsigned char alen = *aStr – 2;   //CRC16只计算前两部分      
   int xda , xdapoly ;          
   int i,j, xdabit ;           
   xda = 0xFFFF ; 
  xdapoly = 0xA001 ; // (X**16 + X**15 + X**2 + 1)  
  for(i=0;i<data.length;i++)        
  {        
  xda ^= data[i] ;
  for(j=0;j<8;j++) {        
   xdabit =( int )(xda & 0x01) ;        
   xda >>= 1 ;
  if( xdabit==1 )
   xda ^= xdapoly ;
   }       
  }   
  System.arraycopy(data, 0, temdata, 0, data.length);
  temdata[temdata.length-2] = (int)(xda & 0xFF) ;          
  temdata[temdata.length-1] = (int)(xda>>8) ;    
  return temdata;
  }

//这个主函数用来测试用的
 public static void main(String args[]){
  int[] data={12,25,1,4,10,5,47,2,45,2,3,4,7,5,6,2,45};
  int[] d1=crc(data);
  for(int i=0;i<d1.length;i++)
   System.out.print(d1[i]+" ");
  System.out.println();
  int[] d2=crc(d1);
  for(int i=0;i<d2.length;i++)
   System.out.print(d2[i]+" ");
 }

}

==================================================================================

下面是C++的算法和参考源代码;

4 校验码      
CRC码由发送端计算,放置于发送信息报文的尾部。接收信息的设备再重新计算接收到信息报文的CRC,比较计算得到
的CRC是否与接收到的相符,如果两者不相符,则表明出错。       
校验码的计算多项式为(X16 + X15 + X2 + 1)。       
具体CRC16码的
计算方法是:        
1.预置1个16位的寄存器为十六进制FFFF(即全为1);称此寄存器为CRC寄存器;      
2.把第一个8位二进制数据 (既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器;      
3.把CRC寄存器的内容右移一 位(朝低位)用0填补最高位,并检查右移后的移出位;      
4.如果移出位为0:重复第3步(再次右移一位);         
   如果移出位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;      
5.重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;  
6.重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;      
7.将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换;      
8.最后得到的CRC寄存器内容即为:CRC码。     

参考算法的C语言实现如下。以下程序
计算一个报文的CRC16并填入报文最后两字节。      
void CRC16( unsigned char *aStr ){             
unsigned char alen = *aStr – 2;   //CRC16只计算前两部分      
unsigned int xda , xdapoly ;          
unsigned char i,j, xdabit ;           
 xda = 0xFFFF ;       
xdapoly = 0xA001 ; // (X**16 + X**15 + X**2 + 1)           
for(i=0;i<alen;i++)        
{        
xda ^= aStr[i] ;        
for(j=0;j<8;j++) {        
 xdabit =(unsigned char )(xda & 0x01) ;        
 xda >>= 1 ;         
if( xdabit )
 xda ^= xdapoly ;  
 }       
}              
aStr[alen-2] = (unsigned char)(xda & 0xFF) ;          
aStr[alen-1] = (unsigned char)(xda>>8) ;      
}

===============================================================================

以代码仅供参考,如有不明白或建议请联系我,共同交流,email:hnbcjzj@163.com

另外提供一个网上找的java crc校验的源程序,我没怎么研究,

import java.io.IOException;
 
public class CRC16Checker {
 
            private static int[] index = new int[] { 16, 15, 2, 0 };
 
            private static int[] getBinary(String text) {
                        StringBuffer num = new StringBuffer();
                        String s; char ch;
                        for (int i = 0; i < text.length(); i++) { // Change each char to binary code.
                                    s = Integer.toBinaryString(text.charAt(i));
                                    // If the code is less than 8 bit, make it as 8 bit.
                                    for (int j = 8 - s.length(); j > 0; j--) num.append(0);
                                    num.append(s);
                        }
                        int len = num.length();
                        int[] code = new int[len];
                        for (int i = 0; i < len; i++) // Change each 0/1 char to int.
                            code[i] = Character.getNumericValue(num.charAt(i));
                        return code;
            }
 
            private static String toHex(int[] num) {
                        StringBuffer hex = new StringBuffer(num.length / 4);
                        char[] ch = new char[4];
                        for (int i = 0; i < num.length;) {
                            // Change each 0/1 int to char.
                                    ch[0] = Character.forDigit(num[i++], 2);
                                    ch[1] = Character.forDigit(num[i++], 2);
                                    ch[2] = Character.forDigit(num[i++], 2);
                                    ch[3] = Character.forDigit(num[i++], 2);
                                    // Change each 4-bit-code to hex number.
                                    hex.append(Integer.toHexString(Integer.parseInt(String.valueOf(ch), 2)));
                        }
                        return hex.toString();
            }
 
// CRC codes main process
            public static int[] makeCRCCodes(int[] sourceCodes, int[] multinomial) {
                        // The lenght of CRC code is N bits longer than source code. The codes
                        // from 0 to sourceLength are same as the source. N bits after source
                        // are the CRC codes. N is decided by the multinomial.
                        // CRC码数组总长为原码长加上校验码码长。数组前部存放原码。校验码存放在数组
                        // 最后的N位。校验码长度决定于生成多项式数组0位置上的元素。
                        int sourceLength = sourceCodes.length;
                        int codesLength = sourceLength + multinomial[0];
                        int[] crcCodes = new int[codesLength];
                        // Copy source code from 0 to sourceLength. 拷贝原码。
                        System.arraycopy(sourceCodes, 0, crcCodes, 0, sourceLength);
                        int temp, pos;
                        // Division system. 除法器。
                        for (int i = 0; i < sourceLength; i++) {
                                    // Count value of the input adding the first register.
                                    // 用第i位原码和第一个寄存器值模二加。
                                    temp = (crcCodes[sourceLength] + sourceCodes[i]) % 2;
                                    // Move registers forwards from (1, length) to (0, length - 1).
                                    // 第二个寄存器及以后的所有寄存器值前移1位。
                                    System.arraycopy(
                                                crcCodes, sourceLength + 1, crcCodes, sourceLength, multinomial[0] - 1);
                                    // Set the last register with counted value.
                                    // 最后一个寄存器值存放计算好的输入值。
                                    crcCodes[codesLength - 1] = temp;
                                    // Count other registers. 按生成多项式的值算出位置,模二加出该寄存器的值。
                                    for (int j = index.length - 2; j > 0; j--) {
                                                pos = codesLength - multinomial[j] - 1;
                                                crcCodes[pos] = (crcCodes[pos] + temp) % 2;
                                    }
                        }
                        return crcCodes;
            }
 
            public static void main(String[] args) throws IOException {
                        System.out.print("Input hex data :");
                        StringBuffer buf = new StringBuffer();
                        char ch = (char) System.in.read();
                        while (ch != '/r' && ch != '/n') {
                                    buf.append(ch);
                                    ch = (char) System.in.read();
                        }
                        // Get binary codes.
                        int[] b = CRC16Checker.getBinary(buf.toString());
                        // Make CRC codes.
                        b = CRC16Checker.makeCRCCodes(b, CRC16Checker.index);
                        // Output code as binary number.
                        for (int i = 0; i < b.length;) {
                                    for (int j = 0; j < 4; j++, i++) System.out.print(b[i]);
                                    System.out.print(' ');
                        }
                        System.out.println();
                        // Output code as hex number.
                        System.out.println("The CRC16 code is :" + CRC16Checker.toHex(b));
            }
}

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2023 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "can.h" #include "tim.h" #include "gpio.h" #include <stdio.h> #include <stdint.h> /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ CAN_TxHeaderTypeDef TXHeader1; //CAN_RxHeaderTypeDef RXHeader1; CAN_TxHeaderTypeDef TXHeader2; CAN_RxHeaderTypeDef RXHeader2; uint8_t H[50]={0}; uint8_t E[50]={0}; uint8_t NCell=40; uint8_t SCmd; uint8_t NE=0; uint8_t NEE=0; //针对一个回“Y”的子节点都没有的情况 uint8_t NH=0; uint8_t n=0; uint8_t CRCJC=0; uint32_t CRC_START=0xFFFFFFFF; uint32_t CRC_OVER=0; uint8_t num; uint8_t num1; uint8_t num2; uint8_t num3; uint8_t num4; uint32_t crc; uint32_t crc_set; uint32_t result; uint32_t poly=0x04C11DB7; uint16_t clearCAN_Rxdata_LZG=0; uint8_t m=0; uint8_t mm=0; uint8_t c=0; uint8_t i=0; uint8_t size=4; uint8_t Error[4]={0x42,0x02,0,0}; uint8_t HAND[8]; uint8_t YAND[2]; uint8_t ZAND[3]; uint8_t RR[2]; uint8_t AS[3]; uint8_t TX0[7]; uint8_t TX1[8]; uint8_t TX2[8]; uint8_t TX3[8]; uint8_t TX4[8]; uint8_t TX5[4]; uint8_t QX0[1]={0x52}; uint8_t zxnumbers[3]; uint8_t pxnumbers[3]; uint32_t zzxnumbers[2]; uint32_t ppxnumbers[2]; uint32_t zzzxnumbers[4]; uint32_t pppxnumbers[4]; uint32_t fxmax; uint32_t zxmax; uint32_t pxmax; uint8_t dmax; uint8_t xmax; uint8_t max; uint8_t b[10]={0}; //uint8_t b2; //uint8_t b3; //uint8_t b4; //uint8_t b5; uint64_t combine_bytes(uint8_t b0,uint8_t b1,uint8_t b2,uint8_t b3,uint8_t b4) { return ((uint64_t)b0 << 32) | ((uint64_t)b1 << 24) | ((uint64_t)b2 << 16) | ((uint64_t)b3 << 8) | (uint64_t)b4; } uint64_t csq; uint8_t NQ; uint8_t NL;//CRC不通过的子节点的数据的重发次数 uint8_t TXmessage2[8]; uint8_t RXmessage2[8]; uint32_t pTxMailbox = 0; uint8_t RxData[8]; uint8_t Data[8]; uint8_t DataH[2]; uint8_t DataA[3]; uint8_t Dataa[8]; uint8_t Dataaa[8]; uint8_t NT; //定时器计数值 uint32_t TxMailbox; uint8_t CAN_Rxdata_LZG[40*3*8*2];//总数据:0X43、0X00、0X40、64个字节数据+0X44、0X04、0X80、1152个字节数据 uint8_t RX_LEN_CAN=0; uint8_t stage; uint8_t stageZ='O'; uint8_t gu7SCIStatus=0; uint8_t gu2SCIStatus=0; uint8_t gu3SCIStatus=0; uint32_t NData;//实际收到的数据长度 uint32_t NDataa; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void);//系统时钟初始化 /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ void CAN1_Send_Stage(uint8_t Data)//主节点与上位机握手 { TXHeader1.StdId=ID1;// 标准标识符为0 TXHeader1.ExtId=0x00; // 设置扩展标示符(29位) TXHeader1.IDE=0; // 使用标准标识符 TXHeader1.RTR=0; // 消息类型为数据帧 TXHeader1.DLC=1; HAL_CAN_AddTxMessage(&hcan1,&TXHeader1,&Data,&pTxMailbox); while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)!=3);//3个发送邮箱都为空时跳出循环 } void CAN1_Send_Msg(uint8_t* Data,uint8_t len)//连续取8个字节的地址 { TXHeader1.StdId=ID1;// 标准标识符为0 TXHeader1.ExtId=0x00; // 设置扩展标示符(29位) TXHeader1.IDE=0; // 使用标准标识符 TXHeader1.RTR=0; // 消息类型为数据帧 TXHeader1.DLC=len; HAL_CAN_AddTxMessage(&hcan1,&TXHeader1,Data,&pTxMailbox); while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)!=3); } void CAN1_Send_error(uint8_t Data1,uint8_t Data2) { uint8_t Data[4]; //定义一个长度为4的数组,用于存储要发送的CAN消息数据 Data[0]=Data1; Data[1]=0x02; Data[2]=(Data2>>8)&0xFF;// Data[3]=Data2&0xFF;// TXHeader1.StdId=ID1;// 标准标识符为0 TXHeader1.ExtId=0x00; // 设置扩展标示符(29位) TXHeader1.IDE=0; // 使用标准标识符 TXHeader1.RTR=0; // 消息类型为数据帧 TXHeader1.DLC=4; HAL_CAN_AddTxMessage(&hcan1,&TXHeader1,Data,&pTxMailbox); while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)!=3); } void CAN2_Send_Msg(uint8_t* Data,uint8_t len,uint8_t IDX) { TXHeader2.StdId=IDX; // 标准标识符为0 TXHeader2.ExtId=0x00; // 设置扩展标示符(29位) TXHeader2.IDE=0; // 使用标准标识符 TXHeader2.RTR=0; // 消息类型为数据帧 TXHeader2.DLC=len; HAL_CAN_AddTxMessage(&hcan2,&TXHeader2,Data,&pTxMailbox); while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan2)!=3); } void CAN2_Send_Stage(uint8_t Data,uint8_t IDX) { TXHeader2.StdId=IDX; // 标准标识符为0 TXHeader2.ExtId=0x00; // 设置扩展标示符(29位) TXHeader2.IDE=0; // 使用标准标识符 TXHeader2.RTR=0; // 消息类型为数据帧 TXHeader2.DLC=1; HAL_CAN_AddTxMessage(&hcan2,&TXHeader2,&Data,&pTxMailbox); while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan2)!=3); } void find_max(uint32_t *numbers, int size) //算最大步数 { fxmax = numbers[0]; for (i = 1; i < size; i++) { if (numbers[i] > fxmax) { fxmax = numbers[i]; } } } //声明 void CAN2_HAND_CMD(); void CAN2_HAND_RESH(); void CAN2_HAND_HH(); void CAN2_STOP_CMD(); void CAN2_STOP_RESH(); void CAN2_STOP_HH(); void CAN2_RUNNING_CMD(); void CAN2_RUN_RR(); void CAN2_RUN_RESR(); void CAN2_RUN_RRR(); void CAN2_RUN_ASK(); void CAN2_RUN_EE(); void CAN2_RUNNING_END(); void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan) //来自子节点的消息 { if(hcan->Instance==CAN2) //若寄存器基地址为CAN2 { HAL_CAN_GetRxMessage(hcan,CAN_FILTER_FIFO1,&RXHeader2,RXmessage2);//获取数据 if(RXmessage2[0]==0x48) //"H" { n=RXHeader2.StdId; if(H[n]=='D') { H[n]='H'; NE++;//子节点回的信号数 } if(H[n]!='D'&&H[n]!='H') { H[n]='B'; } if(NE==NH) { CAN2_HAND_HH(); } } if(RXmessage2[0]==0x53) //"S" { n=RXHeader2.StdId; if(H[n]=='D') { H[n]='S'; NE++;//子节点回的信号数 } if(H[n]!='D'&&H[n]!='S') { H[n]='B'; } if(NE==NH) { CAN2_STOP_HH(); } } if(RXmessage2[0]==0x59) //"Y" { n=RXHeader2.StdId; if(H[n]=='H') { H[n]='R'; NE++; NEE++; } if(H[n]!='H'&&H[n]!='R') { H[n]='B'; } if(NE==NH) { NE=0; CAN2_RUN_RRR(); } } else if(RXmessage2[0]==0x45) //"E" { n=RXHeader2.StdId; if(H[n]=='R') { H[n]='E'; NE++; } if(H[n]!='R'&&H[n]!='E') { H[n]='B'; } if(NE==NH) { CAN2_RUNNING_END(); } } else if(RXmessage2[0]==0x54) //"T" { n=RXHeader2.StdId; ZAND[0]=RXmessage2[0]; ZAND[1]=RXmessage2[1]; ZAND[2]=n; CAN1_Send_Msg(ZAND,3); } else if(RXmessage2[0]==0x58) //"X" { n=RXHeader2.StdId; ZAND[0]=RXmessage2[0]; ZAND[1]=RXmessage2[1]; ZAND[2]=n; CAN1_Send_Msg(ZAND,3); } else if(RXmessage2[0]==0x4C) //"L" { if(NL==2) { NL=0; n=RXHeader2.StdId; ZAND[0]=RXmessage2[0]; ZAND[1]=RXmessage2[1]; ZAND[2]=n; CAN1_Send_Msg(ZAND,3); } else { n=RXHeader2.StdId; TX0[0]=0X44; TX0[1]=DataH[1]; TX0[2]=b[0]; for(i=0;i<=7;i++) { TX1[i]=CAN_Rxdata_LZG[i+0+(n-1)*24]; TX2[i]=CAN_Rxdata_LZG[i+8+(n-1)*24]; TX3[i]=CAN_Rxdata_LZG[i+16+(n-1)*24]; } crc=CRC_START; mm=0; for(mm=1+3*(n-1);mm<=3*n;mm++) { for(c=0;c<8;c++) { crc = crc^(CAN_Rxdata_LZG[c+8*(mm-1)]<<24) ; for (i = 0; i < 8; i++) { if (crc & 0x80000000) { crc = (crc << 1)^poly; } else { crc <<= 1; } } } } crc = crc^CRC_OVER; for(i=3;i<7;i++) //将32位CRC码拆4个8位的CRC码存入TX0[i]中 { TX0[9-i] = (crc>>((i-3)*8))& 0xFF; //TX0[3]= 低8位,TX0[4]= 9-16位,TX0[5]= 17-24位,TX0[6]= 25-32位 }//CRC CAN2_Send_Msg(TX0,7,n); CAN2_Send_Msg(TX1,8,n); CAN2_Send_Msg(TX2,8,n); CAN2_Send_Msg(TX3,8,n); RR[0]=0x52; RR[1]=DataH[1]; CAN2_Send_Msg(RR,2,n); NL++; } } } } void CAN2_HAND_CMD(void) //主节点接收Check命令后,开始向子节点握手 { YAND[0]=0x59; YAND[1]=Data[1]; CAN1_Send_Msg(YAND,2); HAND[0]=0x48; HAND[1]=Data[1]; csq=combine_bytes(b[0],b[1],b[2],b[3],b[4]); for(n=1;n<=NCell;n++) { switch((csq>>(NCell-n))&1) //修改NCell时此处必须更改!!! { case 1: CAN2_Send_Msg(HAND,2,n); H[n]='D'; NH++; break; } if(n==NCell) { NT=0; stage='C'; HAL_TIM_Base_Start_IT(&htim6); NT=0; //也许可以,待测试 } } } void CAN2_HAND_RESH(void) { HAL_TIM_Base_Stop_IT(&htim6); NT=0;//测试 if(NE==NH||NQ==1) { NQ=0; CAN2_HAND_HH(); } else { for(n=1;n<=NCell;n++) { if(H[n]=='D') { // HAND[0]=0x55; //测试 CAN2_Send_Msg(HAND,2,n); } } NQ++; NT=0; stage='C'; HAL_TIM_Base_Start_IT(&htim6); NT=0; //也许可以,待测试 } } void CAN2_HAND_HH(void) { HAL_TIM_Base_Stop_IT(&htim6); NT=0;//测试 for(n=1;n<=NCell;n++) { if(H[n]=='D'||H[n]=='B') { Data[0]=0x42; Data[1]=HAND[1]; Data[2]=n; Data[3]=2; CAN1_Send_Msg(Data,4); } } Data[0]=0x45; Data[1]=HAND[1]; CAN1_Send_Msg(Data,2); stageZ='O'; Data[0]=Data[1]=b[0]=b[1]=b[2]=b[3]=b[4]=0; csq=0; NE=NH=0; NQ=0; } void CAN2_STOP_CMD(void) //主节点接收Stop命令后,开始向子节点Stop { YAND[0]=0x59; YAND[1]=Data[1]; CAN1_Send_Msg(YAND,2); HAND[0]=0x53; HAND[1]=Data[1]; csq=combine_bytes(b[0],b[1],b[2],b[3],b[4]); for(n=1;n<=NCell;n++) { switch((csq>>(NCell-n))&1) //修改NCell时此处必须更改!!! { case 1: CAN2_Send_Msg(HAND,2,n); H[n]='D'; NH++; break; } if(n==NCell) { NT=0; stage='S'; HAL_TIM_Base_Start_IT(&htim6); NT=0; //也许可以,待测试 } } } void CAN2_STOP_RESH(void) { HAL_TIM_Base_Stop_IT(&htim6); NT=0;//测试 if(NE==NH||NQ==2) { NQ=0; CAN2_STOP_HH(); } else { for(n=1;n<=NCell;n++) { if(H[n]=='D') { CAN2_Send_Msg(HAND,2,n); } } NQ++; NT=0; stage='S'; HAL_TIM_Base_Start_IT(&htim6); NT=0; //也许可以,待测试 } } void CAN2_STOP_HH(void) { HAL_TIM_Base_Stop_IT(&htim6); NT=0;//测试 for(n=1;n<=NCell;n++) { if(H[n]=='D'||H[n]=='B') { Data[0]=0x42; Data[1]=HAND[1]; Data[2]=n; Data[3]=2; CAN1_Send_Msg(Data,4); } H[n]=0; } Data[0]=0x45; Data[1]=HAND[1]; CAN1_Send_Msg(Data,2); stageZ='O'; NE=NH=0; NQ=0; } void CAN2_RUNNING_CMD(void) //主节点接收上位机发来的运数据,并按需发给相应的子节点 { //CRC校验→上位机通讯 num1 = b[1]; num2 = b[2]; num3 = b[3]; num4 = b[4]; result = (num1 << 24) | (num2 << 16) | (num3 << 8) | num4; num=3*40; //修改NCell时此处必须更改, 3*3实际为3*(上位机有发送数据的子节点的总个数,未必是40)!!!!!! crc=CRC_START; mm=0; for(mm=0;mm<num;mm++) { for(c=0;c<8;c++) { crc = crc^(CAN_Rxdata_LZG[c+8*mm]<<24) ; for (i = 0; i < 8; i++) { if (crc & 0x80000000) { crc = (crc << 1)^poly; } else { crc <<= 1; } } } } crc = crc^CRC_OVER; if(crc!=result) { Data[0]=0x4C;//CRC校验出错会向上位机报"L" Data[1]=DataH[1]; Data[2]=0; Data[3]=0x02;//轴序号为两轴 CAN1_Send_Msg(Data,4); YAND[0]=0x4C; YAND[1]=NDataa; CAN1_Send_Msg(YAND,2); for (clearCAN_Rxdata_LZG = 0; clearCAN_Rxdata_LZG < 40*3*8*2; clearCAN_Rxdata_LZG++) { CAN_Rxdata_LZG[clearCAN_Rxdata_LZG] = 0; } NData=0; NDataa=0; } else //如果对 { stageZ='R'; HAND[0]=0x59; //CRC校验通过,先回“Y” HAND[1]=DataH[1]; CAN1_Send_Msg(HAND,2); TX0[0]=0X44; TX0[1]=DataH[1]; TX0[2]=b[0]; zxmax = 0; pxmax = 0; dmax = 0; xmax = 0; for(n=1;n<=NCell;n++) { for(i=0;i<=7;i++) { TX1[i]=CAN_Rxdata_LZG[i+0+(n-1)*24]; TX2[i]=CAN_Rxdata_LZG[i+8+(n-1)*24]; TX3[i]=CAN_Rxdata_LZG[i+16+(n-1)*24]; } m = 0; for(i=0;i<=7;i++) { if(TX1[i]!=0) { m=1; } } for(i=0;i<=7;i++) { if(TX2[i]!=0) { m=1; } } for(i=0;i<=7;i++) { if(TX3[i]!=0) { m=1; } } if(m==1) { m=0; crc=CRC_START;//CRC→发送给子节点 mm=0; for(mm=1+3*(n-1);mm<=3*n;mm++) { for(c=0;c<8;c++) { crc = crc^(CAN_Rxdata_LZG[c+8*(mm-1)]<<24) ; for (i = 0; i < 8; i++) { if (crc & 0x80000000) { crc = (crc << 1)^poly; } else { crc <<= 1; } } } } crc = crc^CRC_OVER; for(i=3;i<7;i++) //将32位CRC码拆4个8位的CRC码存入TX0[i]中 { TX0[9-i] = (crc>>((i-3)*8))& 0xFF; //TX0[3]= 低8位,TX0[4]= 9-16位,TX0[5]= 17-24位,TX0[6]= 25-32位 } //判断是大单元还是小单元 if (TX2[0] == 0xFF&&TX2[1] == 0xFF&&TX2[2] == 0xFF&&TX2[3] == 0xFF) { for(c=1;c<2;c++) //算时间,适用于大单元 { for (i = 0; i < 2; i++) { zxnumbers[0]=CAN_Rxdata_LZG[4*i+8*(n-1)+16*(n-1)]&0x3F; zxnumbers[1]=CAN_Rxdata_LZG[4*i+1+8*(n-1)+16*(n-1)]; zxnumbers[2]=CAN_Rxdata_LZG[4*i+2+8*(n-1)+16*(n-1)]&0x80; zxnumbers[2]=zxnumbers[2]>>7; pxnumbers[0]=CAN_Rxdata_LZG[4*i+2+8*(n-1)+16*(n-1)]&0x7F; pxnumbers[1]=CAN_Rxdata_LZG[4*i+3+8*(n-1)+16*(n-1)]; zzxnumbers[i]=(zxnumbers[0]*512+zxnumbers[1]*2+zxnumbers[2])*4;//2的10次方=1024,2的2次方=4 ppxnumbers[i]=(pxnumbers[0]*256+pxnumbers[1])*4; } zzzxnumbers[c]= zzxnumbers[0]+zzxnumbers[1]; pppxnumbers[c]= ppxnumbers[0]+ppxnumbers[1]; } fxmax = zzzxnumbers[1]; if (zxmax < fxmax) { zxmax = fxmax; } fxmax = pppxnumbers[1]; if (pxmax < fxmax) { pxmax = fxmax; } zxmax = (zxmax*27/14336+5)/5 + 1;//得改 pxmax = (pxmax*36/18432+5)/5 + 1;//得改 if (zxmax <= pxmax ) { dmax = pxmax; } else { dmax = zxmax; } } else { for(c=1;c<4;c++) //算时间,适用于小单元 { for (i = 0; i < 2; i++) { zxnumbers[0]=CAN_Rxdata_LZG[4*i+8*n*c-8]&0x3F; zxnumbers[1]=CAN_Rxdata_LZG[4*i+1+8*n*c-8]; zxnumbers[2]=CAN_Rxdata_LZG[4*i+2+8*n*c-8]&0xC0; zxnumbers[2]=zxnumbers[2]>>6; pxnumbers[0]=CAN_Rxdata_LZG[4*i+2+8*n*c-8]&0x3F; pxnumbers[1]=CAN_Rxdata_LZG[4*i+3+8*n*c-8]; zzxnumbers[i]=(zxnumbers[0]*1024+zxnumbers[1]*4+zxnumbers[2])*2;//2的10次方=1024,2的2次方=4 ppxnumbers[i]=pxnumbers[0]*256+pxnumbers[1]; } zzzxnumbers[c]= zzxnumbers[0]+zzxnumbers[1]; pppxnumbers[c]= ppxnumbers[0]+ppxnumbers[1]; } //调用函数 find_max(zzzxnumbers, size); if (zxmax < fxmax) { zxmax = fxmax; } find_max(pppxnumbers, size); if (pxmax < fxmax) { pxmax = fxmax; } zxmax = (zxmax*30/85729.13+5)/5 + 2; //10实验完要去掉 pxmax = (pxmax*30/32386.56+5)/5 + 2; //10实验完要去掉 if (zxmax <= pxmax ) { xmax = pxmax; } else { xmax = zxmax; } } CAN2_Send_Msg(TX0,7,n);//其中后四字节为CRC码 CAN2_Send_Msg(TX1,8,n); CAN2_Send_Msg(TX2,8,n); CAN2_Send_Msg(TX3,8,n); } if (dmax <= xmax ) { max = xmax; } else { max = dmax; } } CAN2_RUN_RR(); } } void CAN2_RUN_RR(void) //发送运命令“R” { RR[0]=0x52; RR[1]=DataH[1]; for(n=1;n<=NCell;n++) { for(i=0;i<=7;i++) { TX1[i]=CAN_Rxdata_LZG[i+0+(n-1)*24]; TX2[i]=CAN_Rxdata_LZG[i+8+(n-1)*24]; TX3[i]=CAN_Rxdata_LZG[i+16+(n-1)*24]; } m = 0; for(i=0;i<=7;i++) { if(TX1[i]!=0||TX2[i]!=0||TX3[i]!=0) { m=1; } } if(m==1&&H[n]=='H') { CAN2_Send_Msg(RR,2,n); NH++; } else { H[n]=0; } if(n==NCell) { NT=0; stage='R'; HAL_TIM_Base_Start_IT(&htim6); NT=0; //也许可以,待测试 } } if(NH==0) //针对一个需要发“R”的子节点都没有的情况 { CAN2_RUNNING_END(); } } void CAN2_RUN_RESR(void) //重发运命令“R” { HAL_TIM_Base_Stop_IT(&htim6); NT=0;//测试 RR[0]=0x52; RR[1]=DataH[1]; if(NE==NH||NQ==2) { NQ=0; CAN2_RUN_RRR(); } else { for(n=1;n<=NCell;n++) { if(H[n]=='H') { CAN2_Send_Msg(RR,2,n); } } NQ++; NT=0; stage='R'; HAL_TIM_Base_Start_IT(&htim6); NT=0; //也许可以,待测试 } } //void CAN2_RUN_RRR(void) //原版 //{ // HAL_TIM_Base_Stop_IT(&htim6); // NT=0;//测试 // for(n=1;n<=NCell;n++) // { // if(H[n]=='H'||H[n]=='B')//对于回比发多和回与发数量相等但不一致的情况,直接向上位机报“B” // { // Data[0]=0x42; // Data[1]=DataH[1]; // Data[2]=n; // Data[3]=2; // CAN1_Send_Msg(Data,4); // } // } // CAN2_RUN_EE(); //} void CAN2_RUN_RRR(void) //新版 { HAL_TIM_Base_Stop_IT(&htim6); NT=0;//测试 if(NEE!=0) //针对一个回“Y”的子节点都没有的情况 { for(n=1;n<=NCell;n++) { if(H[n]=='H'||H[n]=='B')//对于回比发多和回与发数量相等但不一致的情况,直接向上位机报“B” { Data[0]=0x42; Data[1]=DataH[1]; Data[2]=n; Data[3]=2; CAN1_Send_Msg(Data,4); } } CAN2_RUN_EE(); } else { CAN2_RUNNING_END(); } } void CAN2_RUN_EE(void) //给运留max时间 { NT=0; stage='E'; HAL_TIM_Base_Start_IT(&htim6); NT=0; //也许可以,待测试 NQ=0; } void CAN2_RUN_ASK(void) { HAL_TIM_Base_Stop_IT(&htim6); NT=0;//测试 if(NE==NH||NQ==2) { NQ=0; CAN2_RUNNING_END(); } else { AS[0]=0x41; AS[1]=RR[1]; AS[2]=0x52; for(n=1;n<=NCell;n++) { if(H[n]=='R') { CAN2_Send_Msg(AS,3,n); } } NQ++; NT=0; stage='A'; HAL_TIM_Base_Start_IT(&htim6); NT=0; //也许可以,待测试 } } void CAN2_RUNNING_END(void) //检测子节点是否按所发数据运 { HAL_TIM_Base_Stop_IT(&htim6); NT=0;//测试 for(n=1;n<=NCell;n++) { if(H[n]=='H'||H[n]=='R'||H[n]=='B') { Data[0]=0x42; Data[1]=DataH[1]; Data[2]=n; Data[3]=2; CAN1_Send_Msg(Data,4); H[n]='D'; } else { H[n]='H'; } } Data[0]=0x45; Data[1]=HAND[1]; CAN1_Send_Msg(Data,2); stageZ='O'; crc=0; result=0; NData=0; NDataa=0; NEE=NE=NH=0; NQ=0; } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //实时监测:被迫进行下一步 { NT++; if(NT==2&&stage=='C')//&&是逻辑与 { CAN2_HAND_RESH(); } if(NT==2&&stage=='S')//&&是逻辑与 { CAN2_STOP_RESH(); } if(NT==1&&stage=='R')//&&是逻辑与 { CAN2_RUN_RESR(); } if(NT==max*2&&stage=='E') { CAN2_RUN_ASK(); } if(NT==2&&stage=='A') { CAN2_RUN_ASK(); //一轮询问结束后 } } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_CAN1_Init(); MX_CAN2_Init(); MX_TIM6_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim6); HAL_TIM_Base_Stop_IT(&htim6); NT=0; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ while (1) { if(gu2SCIStatus==2) { gu2SCIStatus=0; if(DataH[0]==0x48) { CAN1_Send_Msg(DataH,2); } if(DataH[0]==0x52) { if(stageZ=='S') { YAND[0]=0x58; YAND[1]=0x53; CAN1_Send_Msg(YAND,2); } if(stageZ=='C') { YAND[0]=0x58; YAND[1]=0x43; CAN1_Send_Msg(YAND,2); } if(stageZ=='R') { if(HAND[1]==DataH[1]) { YAND[0]=0x59; YAND[1]=DataH[1]; CAN1_Send_Msg(YAND,2); } else { YAND[0]=0x58; YAND[1]=0x52; CAN1_Send_Msg(YAND,2); } } if(stageZ=='O') { if(HAND[1]==DataH[1]) { YAND[0]=0x54; YAND[1]=RR[1]; CAN1_Send_Msg(YAND,2); } else { CAN2_RUNNING_CMD(); } } } } else if(gu7SCIStatus==7) { NH=0; //子节点回的信号数 NE=0; //主节点发送子节点个数 switch(Data[0]) { case 0x43: gu7SCIStatus=0; switch(stageZ) { case 'S': YAND[0]=0x58; YAND[1]=0x53; CAN1_Send_Msg(YAND,2); break; case 'R': YAND[0]=0x58; YAND[1]=0x52; CAN1_Send_Msg(YAND,2); break; case 'C': if(Data[1]==HAND[1]) { YAND[0]=0x59; YAND[1]=HAND[1]; CAN1_Send_Msg(YAND,2); } else { YAND[0]=0x58; YAND[1]=0x43; CAN1_Send_Msg(YAND,2); } break; case 'O': stageZ='C'; CAN2_HAND_CMD(); break; } break; case 0x53: gu7SCIStatus=0; switch(stageZ) { case 'C': YAND[0]=0x58; YAND[1]=0x43; CAN1_Send_Msg(YAND,2); break; case 'R': YAND[0]=0x58; YAND[1]=0x52; CAN1_Send_Msg(YAND,2); break; case 'S': if(Data[1]==HAND[1]) { YAND[0]=0x59; YAND[1]=HAND[1]; CAN1_Send_Msg(YAND,2); } else { YAND[0]=0x58; YAND[1]=0x53; CAN1_Send_Msg(YAND,2); } break; case 'O': stageZ='S'; CAN2_STOP_CMD(); break; } break; case 0x44: gu7SCIStatus=0; break; } } else if(gu3SCIStatus==3) { gu3SCIStatus=0; switch(DataA[0]) { case 0x41: switch(DataA[2]) { case 0x43: switch(stageZ) { case 'C': if(DataA[1]==YAND[1]) { YAND[0]=0x57; YAND[1]=YAND[1]; CAN1_Send_Msg(YAND,2); } else { YAND[0]=0x54; YAND[1]=YAND[1]; CAN1_Send_Msg(YAND,2); } break; case 'O': if(DataA[1]==YAND[1]) { YAND[0]=0x45; YAND[1]=YAND[1]; CAN1_Send_Msg(YAND,2); } else { YAND[0]=0x54; YAND[1]=YAND[1]; CAN1_Send_Msg(YAND,2); } break; default: YAND[0]=0x54; YAND[1]=YAND[1]; CAN1_Send_Msg(YAND,2); break; } break; case 0x53: switch(stageZ) { case 'S': if(DataA[1]==YAND[1]) { YAND[0]=0x57; YAND[1]=YAND[1]; CAN1_Send_Msg(YAND,2); } else { YAND[0]=0x54; YAND[1]=YAND[1]; CAN1_Send_Msg(YAND,2); } break; case 'O': if(DataA[1]==YAND[1]) { YAND[0]=0x45; YAND[1]=YAND[1]; CAN1_Send_Msg(YAND,2); } else { YAND[0]=0x54; YAND[1]=YAND[1]; CAN1_Send_Msg(YAND,2); } break; default: YAND[0]=0x54; YAND[1]=YAND[1]; CAN1_Send_Msg(YAND,2); break; } break; case 0x52: switch(stageZ) { case 'R': if(DataA[1]==HAND[1]) { YAND[0]=0x57; YAND[1]=HAND[1]; CAN1_Send_Msg(YAND,2); } else { YAND[0]=0x54; YAND[1]=HAND[1]; CAN1_Send_Msg(YAND,2); } break; case 'O': if(DataA[1]==HAND[1]) { YAND[0]=0x45; YAND[1]=HAND[1]; CAN1_Send_Msg(YAND,2); } else { YAND[0]=0x54; YAND[1]=HAND[1]; CAN1_Send_Msg(YAND,2); } break; default: YAND[0]=0x54; YAND[1]=HAND[1]; CAN1_Send_Msg(YAND,2); break; } break; } } } } } /* USER CODE END 3 */ /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.Prediv1Source = RCC_PREDIV1_SOURCE_HSE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL8; RCC_OscInitStruct.PLL2.PLL2State = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } /** Configure the Systick interrupt time */ __HAL_RCC_PLLI2S_ENABLE(); } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file tim.c * @brief This file provides code for the configuration * of the TIM instances. ****************************************************************************** * @attention * * Copyright (c) 2023 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "tim.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ TIM_HandleTypeDef htim6; /* TIM6 init function */ void MX_TIM6_Init(void) { /* USER CODE BEGIN TIM6_Init 0 */ /* USER CODE END TIM6_Init 0 */ TIM_MasterConfigTypeDef sMasterConfig = {0}; /* USER CODE BEGIN TIM6_Init 1 */ /* USER CODE END TIM6_Init 1 */ htim6.Instance = TIM6; htim6.Init.Prescaler = 63999; // 预分频器:64MHz/(63999+1)=1kHz htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 2500; //周期值:1kHz×2500=2500ms(2.5秒) htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim6) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM6_Init 2 */ /* USER CODE END TIM6_Init 2 */ } void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) { if(tim_baseHandle->Instance==TIM6) { /* USER CODE BEGIN TIM6_MspInit 0 */ /* USER CODE END TIM6_MspInit 0 */ /* TIM6 clock enable */ __HAL_RCC_TIM6_CLK_ENABLE(); /* TIM6 interrupt Init */ HAL_NVIC_SetPriority(TIM6_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM6_IRQn); /* USER CODE BEGIN TIM6_MspInit 1 */ HAL_NVIC_SetPriority(TIM6_IRQn,0, 0); HAL_NVIC_EnableIRQ(TIM6_IRQn); // /* USER CODE END TIM6_MspInit 1 */ } } void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) { if(tim_baseHandle->Instance==TIM6) { /* USER CODE BEGIN TIM6_MspDeInit 0 */ /* USER CODE END TIM6_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM6_CLK_DISABLE(); /* TIM6 interrupt Deinit */ HAL_NVIC_DisableIRQ(TIM6_IRQn); /* USER CODE BEGIN TIM6_MspDeInit 1 */ /* USER CODE END TIM6_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ 分析上述代码,对下面的问题给出解释:为什么在主函数里执行完 NT=0; stage='R'; HAL_TIM_Base_Start_IT(&htim6);后会使NT直接跳变1并且进入CAN2_RUN_RESR();中?
最新发布
08-07
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值