CRC校验的基本思想是利用线性编码理论
C语言版 单片机版 VC版
/*********************************************************************
*文件名:crc16.c
*功能: 计算CRC16循环冗余校验程序,所用方法为计算法 。
**********************************************************************/
unsigned int crc16(unsigned char *str, unsigned char num) //CRC计算子程序
{
unsigned char i,j;
unsigned int crc;
crc=0xffff; //初始化
for (i=0;i
crc^=str[i]&0x00ff; //异或 相异出1
for (j=0;j<8;j++)//
{
if (crc&0x0001)
{
crc>>=1; //移位
crc^=0xa001; //异或 1010 0000 0000 0001
}
else
crc>>=1;
}
}
return(crc);
}
android版 java版 crc16
public class crctest {
public static void main(String[] arg) {
System.out.println("test");
/* byte power = 0x53;
byte num = 0;
byte type = 0x06;
byte pow_con = 0;
byte gncs = 0x01;
byte zkb = 0x02;
short sddl = 20;
short sddy = 42;
short sdgl = 500;
short mcpl = 10;
short mcdl = 5;
short ydl = 5;
byte sj[] = { power, num, type, pow_con, gncs, zkb,
(byte) (sddl * 1000 % 256), (byte) (sddl * 1000 / 256),
(byte) (sddy * 1000 % 256), (byte) (sddy * 1000 / 256),
(byte) (sdgl % 256), (byte) (sdgl / 256), (byte) (mcpl % 256),
(byte) (mcpl / 256), (byte) (mcdl * 1000 % 256),
(byte) (mcdl * 1000 / 256), (byte) (ydl * 1000 % 256),
(byte) (ydl * 1000 / 256) }; // 53 0C 06 00 C8 00 00 0F 39 00 64
*/ // 78
byte sj[]={0x01,0x10,0x00,(byte) 0xC9,0x00,0x10,0x10,(byte) 0xE6,(byte) 0x88,(byte) 0x91,(byte) 0xE6,(byte) 0x98,(byte) 0xAF,(byte) 0xE8,(byte) 0xB0,(byte) 0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
int i, j;
//sj[1] = (byte) (sj.length + 2);
i = (int) crc16(sj, (byte) (sj.length));
//System.out.printf("%4X\n",i); //
for (j = 0; j < (byte) (sj.length); j++)
System.out.printf("%02X ", sj[j]); // 打印
System.out.printf("%02X %02X", (byte)(i % 256), (byte)(i / 256)); // 低字节 高字节 93 25
}
public static int crc16(byte[] str, byte num) // CRC计算子程序
{
byte i, j;
int crc;
crc = (int) (0xffff);
for (i = 0; i < num; i++) {
crc ^= (int) (str[i] & 0x00ff);
for (j = 0; j < 8; j++) {
if ((crc & 0x0001) == 1) {
crc >>= 1;
crc ^= 0xa001;
} else
crc >>= 1;
}
}
return (int)(crc);
}
}
附:测试
#include
/*********************************************************************
*文件名:crc16.c
*功能: 计算CRC16循环冗余校验程序,所用方法为计算法 。
**********************************************************************/
unsigned int crc16(unsigned char *str, unsigned char num) //CRC计算子程序
{
unsigned char i,j;
unsigned int crc;
crc=0xffff; //初始化
for (i=0;i
crc^=str[i]&0x00ff; //异或 相异出1
for (j=0;j<8;j++)//
{
if (crc&0x0001)
{
crc>>=1; //移位
crc^=0xa001; //异或 1010 0001
}
else
crc>>=1;
}
}
return(crc);
}
void main()
{
unsigned char power=0x53;
unsigned char num=0;
unsigned char type=0x06;
unsigned char pow_con=0;
unsigned char gncs=0x01;
unsigned char zkb=0x02;
unsigned int sddl=20;
unsigned int sddy=42 ;
unsigned int sdgl=500;
unsigned int mcpl=10 ;
unsigned int mcdl=5 ;
unsigned int ydl=5 ;
unsigned char sj[]={power,num,type,pow_con,gncs,zkb,sddl*1000%256,sddl*1000/256,sddy*1000%256,sddy*1000/256,sdgl%256,sdgl/256,mcpl%256,mcpl/256,mcdl*1000%256,mcdl*1000/256,ydl*1000%256,ydl*1000/256}; //53 0C 06 00 C8 00 00 0F 39 00 64 78
// unsigned char sj[]={0x53,0x07,0x06,0x00,0x07,0x6C };
unsigned int i,j;
sj[1]=sizeof(sj)+2;
i=crc16(sj,sizeof(sj));
// printf("%4X\n",i); //
for(j=0;j
printf("%02X %02X",i%256,i/256); //低字节 高字节 93 25
while(1);
}
// PSerialPort.h: interface for the CPSerialPort class.
//
//
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//typedef void (*LPDataArriveProc)(char *data,int length,DWORD userdata); //函数指针
class CPSerialPort
{
//扩展
public:
BOOL hexSend; //
BOOL hexReceive;
BOOL SendStr(CString str);
CString ReceiveStr(void);
public:
CPSerialPort();
virtual ~CPSerialPort();
BOOL OpenPort(LPCTSTR Port,int Baudrate,int DataBits,int StopBits,int Parity,DWORD userdata=0); //打开串口
BOOL ClosePort(); //关闭串口
DWORD ReadDataWaiting( void );
DWORD ReadData( void *buffer, DWORD limit );
DWORD WritePort(void *data,int length); //发送数据
DWORD WriteFileToPort(LPCTSTR FileName); //发送文件
unsigned int CPSerialPort::crc16(unsigned char *str, unsigned char num); //CRC计算子程序
private:
HANDLE m_hComm; //串口设备handle
HANDLE m_hReadThread; //读串口线程handle
BOOL m_bReceiving; //是否持续接收
int m_nBufferSize; //缓冲大小
char *Buffer; //缓冲区
// LPDataArriveProc m_lpDataArriveProc;
DWORD m_dwUserData;
//串口设置以及超时参数
DCB dcb;
COMMTIMEOUTS CommTimeOuts;
protected:
OVERLAPPED m_OverlappedRead;
};
// PSerialPort.cpp: implementation of the CPSerialPort class.
//
//接收可以用线程或定时 每次最大接收LIMIT 陈
//默认为十六进制接收与发送 发送时去空格
//
#include "stdafx.h"
//#include "SerialPort.h"
#include "PSerialPort.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define MAX_READ_BUFFER 16384
#define MAX_WRITE_BUFFER 16384
#define LIMIT 100 //接收的最大字节数
//
// Construction/Destruction
//
CPSerialPort::CPSerialPort() //
{
memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );
m_hComm=INVALID_HANDLE_VALUE;//无准句柄值
m_hReadThread=NULL;
m_bReceiving=FALSE;
m_nBufferSize=1024; //缓冲大小
hexSend=TRUE;
hexReceive=TRUE;
}
CPSerialPort::~CPSerialPort()
{
ClosePort();
}
BOOL CPSerialPort::OpenPort(LPCTSTR Port,int BaudRate,int DataBits,int StopBits,int Parity,DWORD userdata)
{
m_dwUserData=userdata;
if(m_hComm==INVALID_HANDLE_VALUE)
{
m_hComm=CreateFile(Port,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0); // OPEN_EXISTING, //打开现有的还不是创建 // 同步I/O操作
if(m_hComm==INVALID_HANDLE_VALUE )
{
AfxMessageBox(_T("无法打开端口!请检查是否已被占用。"));
return FALSE;
}
GetCommState(m_hComm,&dcb); //获取串口的初始配置
dcb.BaudRate=BaudRate; //波特率,指定通信设备的传输速率。
dcb.ByteSize=DataBits; // 通信字节位数,4—8
dcb.Parity=Parity; //奇偶校验方法
dcb.StopBits=StopBits; //指定停止位的位数。
dcb.fParity=FALSE;
dcb.fBinary=TRUE;
dcb.fDtrControl=0;
dcb.fRtsControl=0;
dcb.fOutX=dcb.fInX=dcb.fTXContinueOnXoff=0;
//设置状态参数
SetCommMask(m_hComm,EV_RXCHAR); //指定一组监视通信设备的事件 EV_RXCHAR:输入缓冲区中已收到数据,即接收到一个字节并放入输入缓冲区。
SetupComm(m_hComm,MAX_READ_BUFFER,MAX_WRITE_BUFFER); //设置I/O缓冲区的大小
if(!SetCommState(m_hComm,&dcb)) //设置COM口的设备控制块
{
AfxMessageBox(_T("无法按当前参数配置端口,请检查参数!"));
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR); // 清空缓冲区
ClosePort(); //关闭串口
return FALSE;
}
//设置超时参数 这个一直在读,重新设
//RI:-1 RM:-1 RC:-2 WM:0 WC:0
GetCommTimeouts(m_hComm,&CommTimeOuts); //获取串口的初始超时配置
CommTimeOuts.ReadIntervalTimeout=-1; //最大值0xffff ffff
CommTimeOuts.ReadTotalTimeoutMultiplier=-1;
CommTimeOuts.ReadTotalTimeoutConstant=-2;
CommTimeOuts.WriteTotalTimeoutMultiplier=0;
CommTimeOuts.WriteTotalTimeoutConstant=0;
/*
//设置超时参数 这个一直在读,重新设
GetCommTimeouts(m_hComm,&CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout=100;
CommTimeOuts.ReadTotalTimeoutMultiplier=1;
CommTimeOuts.ReadTotalTimeoutConstant=100;
CommTimeOuts.WriteTotalTimeoutMultiplier=0;
CommTimeOuts.WriteTotalTimeoutConstant=0;
*/
if(!SetCommTimeouts(m_hComm,&CommTimeOuts)) //设置串口的超时配置
{
AfxMessageBox(_T("无法设置超时参数!"));
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
ClosePort();
return FALSE;
}
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
return TRUE;
}
return FALSE;
}
BOOL CPSerialPort::ClosePort()
{
if(m_hComm!=INVALID_HANDLE_VALUE)
{
SetCommMask(m_hComm,0);
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
CloseHandle(m_hComm);
m_hComm=INVALID_HANDLE_VALUE;
return TRUE;
}
return TRUE;
}
DWORD CPSerialPort::ReadDataWaiting( void ) //在使用ReadFile 函数进行读操作前,应先使用ClearCommError函数清除错误。
{
if(m_hComm==INVALID_HANDLE_VALUE || m_hComm == NULL)
return( 0 );
DWORD dwErrorFlags;
COMSTAT ComStat;
ClearCommError( m_hComm, &dwErrorFlags, &ComStat ); //获得通信错误并报告串口的当前状态,同时,该函数清除串口的错误标志以便继续输入、输出操作。
return ( ComStat.cbInQue ); //输入缓冲区的字节数
}
DWORD CPSerialPort::WritePort(void *data,int length)
{
if(m_hComm==INVALID_HANDLE_VALUE)
{
return 0;
}
BOOL fWriteState;
DWORD dwBytesWritten=0;
fWriteState=WriteFile(m_hComm,data,length*sizeof(char),&dwBytesWritten,NULL);
return dwBytesWritten;
}
DWORD CPSerialPort::ReadData( void *buffer, DWORD limit )
{
BOOL bReadStatus;
DWORD dwBytesRead;
dwBytesRead=ReadDataWaiting();
if(dwBytesRead==0) return( 0 );
if(dwBytesRead>limit)
dwBytesRead=limit; //取最小值
bReadStatus = ReadFile( m_hComm, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead );
if( !bReadStatus ){
if( GetLastError() == ERROR_IO_PENDING ){ //GetLastError()函数返回ERROR_IO_PENDING,表明串口正在进行读操作
WaitForSingleObject( m_OverlappedRead.hEvent, 2000 ); //使用WaitForSingleObject函数等待,直到读操作完成或延时已达到2秒钟
//当串口读操作进行完毕后,m_osRead的hEvent事件会变为有信号
return( dwBytesRead ); //返回读到的字节数
}
return( 0 );
}
return( dwBytesRead ); //返回读到的字节数
}
DWORD CPSerialPort::WriteFileToPort(LPCTSTR FileName)
{
if(m_hComm==INVALID_HANDLE_VALUE)
{
return 0;
}
CFile cf;
BOOL fWriteState;
DWORD dwBytesWritten;
DWORD dwCharToWrite;
dwCharToWrite=0;
if(!cf.Open(FileName,CFile::modeRead))
{
//AfxMessageBox(_T("无法打开Hex文件!"));
return 0;
}
dwCharToWrite=(DWORD)cf.GetLength();
cf.Seek(0,CFile::begin);
dwBytesWritten=0;
if(m_hComm!=INVALID_HANDLE_VALUE&&dwCharToWrite!=0)
{
char* buf=new char[dwCharToWrite];
cf.Read(buf,dwCharToWrite);
fWriteState=WriteFile(m_hComm,buf,dwCharToWrite*sizeof(char),&dwBytesWritten,NULL);
if(!fWriteState)
{
//AfxMessageBox(_T("无法向端口写入数据!"));
}
delete[] buf;
}
cf.Close();
return dwBytesWritten;
}
CString CPSerialPort::ReceiveStr(void)
{
//处理收到的数据
unsigned char *data = new unsigned char[LIMIT];
DWORD length= ReadData(data, LIMIT);
if(length)
{
CString THex(_T(""));
CString strDataReceived(_T(""));
if(hexReceive)
{
for(DWORD i=0;i='0'&&str.GetAt(i*2)<='9')||(str.GetAt(i*2)>='A'&&str.GetAt(i*2)<='F'))&&((str.GetAt(i*2+1)>='0'&&str.GetAt(i*2+1)<='9')||(str.GetAt(i*2+1)>='A'&&str.GetAt(i*2+1)<='F')))
{
dwCharToWrite++; //得到字节长度
}
}
}
dwBytesWritten=0;
if(dwCharToWrite)
{
char* buf=new char[dwCharToWrite];
if(!hexSend)
{
for(i=0;i<(int)dwCharToWrite;i++)
{
buf[i]=( char)str.GetAt(i);
}
}
else //以十六进制发送
{
j=0;
for(i=0;i='0'&&str.GetAt(i*2)<='9')||(str.GetAt(i*2)>='A'&&str.GetAt(i*2)<='F'))&&((str.GetAt(i*2+1)>='0'&&str.GetAt(i*2+1)<='9')||(str.GetAt(i*2+1)>='A'&&str.GetAt(i*2+1)<='F')))
{
if(str.GetAt(i*2+1)>='0'&&str.GetAt(i*2+1)<='9')
{
buf[j]=str.GetAt(i*2+1)-48;
}
else
{
buf[j]=str.GetAt(i*2+1)-55;
}
if(str.GetAt(i*2)>='0'&&str.GetAt(i*2)<='9')
{
buf[j]+=(str.GetAt(i*2)-48)*16;
}
else
{
buf[j]+=(str.GetAt(i*2)-55)*16;
}
j++;
}
}
}
dwBytesWritten= WritePort(buf, dwCharToWrite); //写入数据
if(dwBytesWritten==0)
{
AfxMessageBox(_T("无法向端口写入数据!"));
return FALSE;
}
delete[] buf;
}
// Sleep(100);
return TRUE;
}
unsigned int CPSerialPort::crc16(unsigned char *str, unsigned char num) //CRC计算子程序
{
unsigned char i,j;
unsigned int crc;
crc=0xffff;
for (i=0;i>=1;
crc^=0xa001;
}
else
crc>>=1;
}
}
return(crc);
}
Java 校验和
public class test {
public static byte[] str2Byte(String hexStr) {
hexStr = hexStr.replaceAll(" ", ""); // 去空格
if ((hexStr == null) || (hexStr.equals(""))) {
return null;
}
int b = hexStr.length() % 2;
if (b != 0) {
hexStr = "0" + hexStr;
}
String[] a = new String[hexStr.length() / 2];
byte[] bytes = new byte[hexStr.length() / 2];
for (int i = 0; i < bytes.length; i++) {
a[i] = hexStr.substring(2 * i, 2 * i + 2);
}
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) Integer.parseInt(a[i], 16);
}
return bytes;
}
public static int crc16(byte[] str, byte num) // CRC计算子程序
{
byte i, j;
int crc;
crc = (int) (0xffff);
for (i = 0; i < num; i++) {
crc ^= (int) (str[i] & 0x00ff);
for (j = 0; j < 8; j++) {
if ((crc & 0x0001) == 1) {
crc >>= 1;
crc ^= 0xa001;
} else
crc >>= 1;
}
}
return (int)(crc);
}
public static int crcNum(byte[] str, byte num) // CRC计算子程序
{
int crc=0;
for(int i=0;i