modbus通讯主机发送命令校验方法

本文详细介绍了如何在MFC应用中通过Mscomm控件实现Modbus通讯,包括串口初始化、COM选择、数据发送前的CRC校验,以及关键步骤的代码示例。

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

modbus是工业自动化领域常用的通讯协议,主机在从机发送命令的过程中,为了纠错,常常用crc校验。本文就主机部分展开;在MFC方法下可以这样实现;

第一步:在主机主界面增加Mscomm控件,并关联一个变量m_mscomm_1;且增加combo下拉框;

下拉框关联变量m_combo_1;

第二步:在初始化部分BOOL CXXXXXXXDlg::OnInitDialog()的主体部分

写串口的初始化代码,就是调用GetmyCOM()函数;下面为函数;

void CxxxxxxxDlg::GetmyCOM(void)//这里xx用你自己的对话框cpp名称代替
{
	//程序启动时获取全部可用串口
	HANDLE  hCom;
	int i,num,k;
	CString str;
	BOOL flag;

	((CComboBox *)GetDlgItem(IDC_COMBO1))->ResetContent();
	flag = FALSE;
	num = 0;
	for (i = 1;i <= 16;i++)
	{     //此程序支持16个串口
		str.Format(TEXT("\\\\.\\COM%d"), i);

		hCom = CreateFile(str, 0, 0, 0, 
			OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
		if(INVALID_HANDLE_VALUE != hCom )
		{   //能打开该串口,则添加该串口
			CloseHandle(hCom);
			str = str.Mid(4);
			((CComboBox *)GetDlgItem(IDC_COMBO1))->AddString(str);
			if (flag == FALSE)
			{
				flag = TRUE;
				num = i;
			}
		}
	}
	i = ((CComboBox *)GetDlgItem(IDC_COMBO1))->GetCount();
	if (i == 0)
	{//若找不到可用串口则禁用“打开串口”功能
		((CComboBox *)GetDlgItem(IDC_COMBO1))->EnableWindow(FALSE);
	}
	else
	{
		k = ((CComboBox *)GetDlgItem((IDC_COMBO1)))->GetCount();
		((CComboBox *)GetDlgItem(IDC_COMBO1))->SetCurSel(k - 1);
	}


}

这样所有机器上可用的串口都自动显示在了下拉列表框,程序运行时可以用鼠标点取;

第三步打开串口

  voie Open_COM(void) 
{

    UpdateData(TRUE);                   //刷新对话框上的数据到变量
	int index1 = m_combox_1.GetCurSel(); //串口号这个函数用于得到用户选择的是下拉列表中的第几 
    行,第一行的话,返回0,依次类推
	
	CString strcom_number;
	CString strCom;
	m_combox_1.GetLBText(index1,strCom);    //根据行号得到串口号字符串
	int portnumb=0;                         //定义一个空的int变量用来装串口号 
	CString straa=NULL;                     //定义一个空字符串用来装COMX的X;
	straa=(strCom.GetAt(3));                //取得X字符;
	portnumb =_wtoi(straa);               //把字符串COMX(X的值是1到16)的x转为数字
	m_mscomm_1.put_CommPort(portnumb);   //选择串口;对于连续排列的串口号有用
	m_mscomm_1.put_InputMode(1);          //串口二进制形式收发;
	m_mscomm_1.put_Settings(_T("9600,n,8,1"));//设置串口字符发送形式,
		if(!m_mscomm_1.get_PortOpen())
	{
	m_mscomm_1.put_PortOpen(TRUE);//打开串口;

	}
}

第三步,准备发送控制字节数组;

unsigned char senddata[]={0x55,0x06,0x08,0xfa,0xaf,0xda,0,0};

定义一个char类型的数组,其中的数字要根据你下位机和上位机的协议进行

本例senddata[0]=0x55是下位机地址码,

       senddata[0]=0x06是写线圈;

其他的字节自己定;

值得注意的事最后要留下两个字节的空位,先用0占住,以后放crd—modbus校验字,低字节在前高字节在后;以下是校验程序;

void CXXXXXXXXDlg::crc_modebus(unsigned char* charr, unsigned char len)
{
	unsigned int temp ; 
	unsigned char n,i ;
	unsigned char* p1;
	p1=charr;
	temp = 0x0000ffff;
	for( n = 0; n < len; n++)	         //此处的Len是要校验的字节数。
	{       
		temp = *charr ^ temp;
		temp &= 0x0000ffff;
		for( i = 0;i < 8;i++)            //每一个字节8bit,每bit都要处理。
		{ 
			if(temp & 0x01)
			{
				temp = temp >> 1;
				temp &= 0x0000ffff;
				temp = temp ^ 0xa001;
				temp &= 0x0000ffff;
			}   
			else
			{
				temp = temp >> 1;
				temp &= 0x0000ffff;
			}   
		}  
		charr++; 
	}
	*(p1+len)=temp;
	*(p1+len+1)=temp>>8;
	                    
}

调用的时候用crc_modebus(senddata,sizeof(senddata)-2);这里-2就是除了最后的两个字节0,其他的字节都进行校验;

校验的值自动添加到了sendddata字节数组的最后两个字节了;

第四步发送数据;

void CXXXXXXDlg::senddata()
{
	
    unsigned char senddata[]={0x55,0x06,0x08,0xfa,0xaf,0xda,0,0};
     //以上是准备好的数组;
   crc_modebus(senddata,sizeof(senddata)-2);//这是校验
	CByteArray m_sendDate;  //准备一个发送数据类型的变量;
	
	for(int i=0;i<sizeof(senddata);i++)
	{
      m_sendDate.Add(senddata[i]);       //把准备好的数组逐个交给发送类型变量
	}
	m_mscomm_1.put_Output(COleVariant(m_sendDate)); //发送十六进制数据
	
	
}

这样校验好的数据就发送出去了;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值