串口助手+CRC校验(可用于PLC中ModBus通信)

由于我有个朋友在改造设备,需要用到S7-200中的ModBus通信,其中需要CRC校验码。本人查找了很多资料,终于理解了CRC校验码的原理及在CSDN中找到一个有关CRC校验的一个源程序,通过理解及分析,最终写出了这个基于MFC框架下的"串口助手+CRC校验(可用于PLC中ModBus通信)”,已通过串口测试,能正常通信。

代码写得很粗糙,感觉有很多漏洞,由于时间关系没进一步完善,勉强能用啦!

以下为代码的讲解,用的编程环境为VS2012中MFC编程框架写的界面,界面也弄得很粗糙

下面为crc生成代码:

void Ccrc校验V20Dlg::OnBnClickedButton1()//生成crc校验码
{
	UpdateData(true);
	BYTE LinNumber = 0;
	int CstrMount = 0;
	CString CStrZ;
	CString CStrH,CStrL;

	int mountCstr = m_EditCrcYuan.GetLength();//获取数组长度
	std::vector Bian(mountCstr/2);

	for (int i = 0; i < mountCstr/2; i++)
	{
		CStrZ=m_EditCrcYuan.Mid(i*2,2);//分割字符串
		HexToDec(CStrZ,LinNumber);//转16进制
		Bian[i]=LinNumber;
	}

	BYTE CRC_L = 0xff,CRC_H = 0xff;//crc初始值
	BYTE SH = 0x0,SL = 0x0;//临时变量

	for (int mount = 0; mount < mountCstr/2; mount++)
	{
		CRC_L = (BYTE)CRC_L ^ Bian[mount];
		for (int i = 0; i < 8; i++)
		{
			SH = CRC_H;SL = CRC_L;
			CRC_H = (BYTE)(CRC_H >> 1);//高位右移一位
			CRC_H = (BYTE)(CRC_H & 0x7f);
			CRC_L = (BYTE)(CRC_L >> 1);//低位右移一位
			CRC_L = (BYTE)(CRC_L & 0x7f);
			if ((SH & 0x01) == 0x01)//高低字节连接,高位原本最后一个为1,则低位第一个应为1
			{
				CRC_L = (BYTE)(CRC_L | 0x80);
			}
			if ((SL & 0x01) == 1)//如果最低位为1,则与多项式进行异或
			{
				CRC_H = (BYTE)(CRC_H ^ 0xA0);
				CRC_L = (BYTE)(CRC_L ^ 0x01);
			}
		}
	}

	CStrH.Format(_T("%2x"),CRC_H);
	CStrL.Format(_T("%2x"),CRC_L);	
	CStrH.Replace(_T(" "),_T("0"));
	CStrL.Replace(_T(" "),_T("0"));

	m_EditCrcEnd = m_EditCrcYuan +  CStrL + CStrH ;//校验结果

	UpdateData(false);

	return;
}

由于在PLC通信中,通常转换为16进制才发送,可按以下函数进行转换,函数可在网上找到,其作用是将文本框接受到的字符串转为16进制字符,如a转换为0x0a

BOOL   HexToDec(LPCTSTR   shex,BYTE&   idec   )   
{   
    int  i,mid;   
    int  len   =   lstrlen(   shex   );       
    if(len>8)     return   FALSE;      
    mid = 0;idec = 0;   
    for(i=0;i='0'&&shex[i]<='9'   ) mid  = shex[i]-'0';   
       else   if(   shex[i]>='a'&&shex[i]<='f') mid   =   shex[i]   -'a'   +10;   
       else   if(   shex[i]>='A'&&shex[i]<='F') mid   =   shex[i]   -'A'   +10;   
       else   return   FALSE;       
       mid   <<=   ((len-i-1)<<2);   
       idec   |=   mid;       
      }       
      return   TRUE;   
 }  


在串口通信中16进制发送,可通过上面的函数转换为16进制,然后定义一个向量数组,然后发送向量数组

void Ccrc校验V20Dlg::OnBnClickedButton2()//串口发送
{
	UpdateData(TRUE);  //读取编辑框内容

	m_EditReceive = _T("");
	m_EditSend = m_EditCrcEnd;
	UpdateData(false);//数据更新

	CString CStrZ,CstrLin;
	BYTE LinNumber = 0;
	int mountCstr = m_EditCrcEnd.GetLength();//获取数组长度
	std::vector Bian(mountCstr/2);

	CByteArray Array;//存储获取plc数据的指令

	Array.RemoveAll();
	Array.SetSize(mountCstr/2);

	for (int i = 0; i < mountCstr/2; i++)
	{
		CStrZ=m_EditCrcEnd.Mid(i*2,2);//分割字符串
		HexToDec(CStrZ,LinNumber);//转16进制
		Array.SetAt(i,LinNumber);
	}
	m_mscomm.put_Output(COleVariant(Array)); //发送数据
	return;
}



下面为crc在线校验网站,我在于PLC通信时发现高低字节要互换,可能是高低字节发送的顺序不同的原因

https://www.lammertbies.nl/comm/info/crc-calculation.html

下面为本文源程序下载地址

http://download.csdn.net/detail/alfive/9791914

你可能感兴趣的:(软件编程)