关于Modbus上位机与PLC通讯

8 篇文章 0 订阅

1、通过sock通讯读取到PLC传到地址里面去的对应的数据

开一个线程不断刷新地址里的数据,把读到的数据全部保存进一个容器中

2、从地址里获取到的转化出来一般为有符号的整形

bool ModbusBase::getBit(const modbusCell& cell, bool & value)
{
	std::lock_guard<std::mutex> locker(m_mutex);
	m_statusOK = true;
	if (m_manualFlag)
	{
		m_statusOK = manualDeal(cell, true, false);
	}
	std::map<char, std::vector <unsigned short>>* space = m_space[cell.type_];
	switch (cell.type_)
	{
	case ModbusDataType_Coils:		//线圈----读写
	case ModbusDataType_DiscreteInput:	//离散量--只读
	{
		checkSpsce(space, cell.slave_, (cell.addr_ + 15) / 16);
		value = (space->at(cell.slave_)[cell.addr_ / 16] & (0x0001 << cell.addr_ % 16)) > 0;
		break;
	}
	case ModbusDataType_RegisterInput:	//输入寄存器--只读
	case ModbusDataType_RegisterHolding: //保持寄存器--读写
	{
		checkSpsce(space, cell.slave_, cell.addr_);
		value = (space->at(cell.slave_)[cell.addr_] & (0x0001 << (cell.bitAddr_ % 16))) > 0;
		break;
	}
	default:
		break;
	}
	return m_statusOK;
}

bool ModbusBase::setBit(const modbusCell& cell, bool value)
{
	std::lock_guard<std::mutex> locker(m_mutex);
	m_statusOK = true;
	std::map<char, std::vector <unsigned short>>* space = m_space[cell.type_];
	switch (cell.type_)
	{
	case ModbusDataType_Coils:		//线圈----读写
	case ModbusDataType_DiscreteInput:	//离散量--只读
	{
		checkSpsce(space, cell.slave_, (cell.addr_ + 15) / 16);
		unsigned short temp = space->at(cell.slave_)[cell.addr_ / 16];
		if (value) {
			temp = temp | (0x0001 << (cell.addr_ % 16));
		}
		else {
			temp = temp & (~(0x0001 << (cell.addr_ % 16)));
		}
		space->at(cell.slave_)[cell.addr_ / 16] = temp;
		break;
	}
	case ModbusDataType_RegisterInput:	//输入寄存器--只读
	case ModbusDataType_RegisterHolding: //保持寄存器--读写
	{
		checkSpsce(space, cell.slave_, cell.addr_);
		unsigned short temp = space->at(cell.slave_)[cell.addr_];
		if (value) {
			temp = temp | (0x0001 << (cell.bitAddr_ % 16));
		}
		else {
			temp = temp & (~(0x0001 << (cell.bitAddr_ % 16)));
		}
		space->at(cell.slave_)[cell.addr_] = temp;
		break;
	}
	default:
		break;
	}
	if (m_manualFlag)
	{
		m_statusOK = manualDeal(cell, false, false);
	}
	return m_statusOK;
}

bool ModbusBase::getWord(const modbusCell& cell, short & value)
{
	std::lock_guard<std::mutex> locker(m_mutex);


	m_statusOK = true;
	if (m_manualFlag)
	{
		m_statusOK = manualDeal(cell, true, false);
	}
	std::map<char, std::vector <unsigned short>>* space = m_space[cell.type_];
	checkSpsce(space, cell.slave_, cell.addr_);
	value = space->at(cell.slave_)[cell.addr_];
	return m_statusOK;
}

bool ModbusBase::setWord(const modbusCell& cell, short value)
{
	std::lock_guard<std::mutex> locker(m_mutex);
	m_statusOK = true;
	std::map<char, std::vector <unsigned short>>* space = m_space[cell.type_];
	checkSpsce(space, cell.slave_, cell.addr_);
	space->at(cell.slave_)[cell.addr_] = value;
	if (m_manualFlag)
	{
		m_statusOK = manualDeal(cell, false, false);
	}
	return m_statusOK;
}

bool ModbusBase::getInt(const modbusCell& cell, int& value)
{
	std::lock_guard<std::mutex> locker(m_mutex);
	m_statusOK = true;
	if (m_manualFlag)
	{
		m_statusOK = manualDeal(cell, true, false);
	}
	std::map<char, std::vector <unsigned short>>* space = m_space[cell.type_];
	checkSpsce(space, cell.slave_, cell.addr_ + 1);
	//value = space->at(cell.slave_)[cell.addr_] << 16 | space->at(cell.slave_)[cell.addr_ + 1];
	value = space->at(cell.slave_)[cell.addr_] | space->at(cell.slave_)[cell.addr_ + 1] << 16;

	//space里面存的值是一个无符号的十进制数  一个地址2个字节16位
	unsigned int highUnsigned = space->at(cell.slave_)[cell.addr_] & 0xFFFF;  // 将有符号数与 0xFFFF 进行按位与操作  转成无符号十进制
	unsigned int lowUnsigned = space->at(cell.slave_)[cell.addr_ + 1] & 0xFFFF;  // 将有符号数与 0xFFFF 进行按位与操作
	// 合成无符号 32 位数
	uint32_t combinedValue = (static_cast<uint32_t>(highUnsigned) << 16) | lowUnsigned;
	value = combinedValue;
	short s = space->at(cell.slave_)[cell.addr_];
	short s1 = space->at(cell.slave_)[cell.addr_ + 1];
	short s2 = space->at(cell.slave_)[cell.addr_ + 1] << 16;

	return m_statusOK;
}

bool ModbusBase::setInt(const modbusCell& cell, int value)
{
	std::lock_guard<std::mutex> locker(m_mutex);
	m_statusOK = true;
	std::map<char, std::vector <unsigned short>>* space = m_space[cell.type_];
	checkSpsce(space, cell.slave_, cell.addr_ + 1);
	/*space->at(cell.slave_)[cell.addr_ + 0] = (value & 0xffff0000) >> 16;
	space->at(cell.slave_)[cell.addr_ + 1] = value & 0x0000ffff;*/


	/*space->at(cell.slave_)[cell.addr_ + 0] = (value & 0x0000ffff);
	space->at(cell.slave_)[cell.addr_ + 1] = value & 0xffff0000 >> 16;*/

	// 拆分为高位和低位
	int16_t highByte = (value >> 16) & 0xFFFF;
	int16_t lowByte = value & 0xFFFF;

	space->at(cell.slave_)[cell.addr_ + 0] = highByte;
	space->at(cell.slave_)[cell.addr_ + 1] = lowByte;
	if (m_manualFlag)
	{
		m_statusOK = manualDeal(cell, false, false);
	}
	return m_statusOK;
}

bool ModbusBase::getString(const modbusCell& cell, std::string & value)
{
	std::lock_guard<std::mutex> locker(m_mutex);
	m_statusOK = true;
	if (m_manualFlag)
	{
		m_statusOK = manualDeal(cell, true, false);
	}
	std::map<char, std::vector <unsigned short>>* space = m_space[cell.type_];
	checkSpsce(space, cell.slave_, cell.addr_);
	std::vector <unsigned short>& vec = space->at(cell.slave_);
	std::string str;
	str = value;
	//从当前地址逐个往下遍历并将里面的字符提取出来知道提取到0x0000,表示这一个字符串结束  一个地址两个字节16位 
	//默认使用UTF-8编码,一个中文占三个字节  
	//例如 "啊"  汉字 “啊” 的Unicode码点是U+554A  它的UTF-8编码为:0xE5 0x95 0x8A。0xE5(229) 0x95(149)0x8A(138) 十进制数为229 149 138
	for (int i = cell.addr_; i < vec.size(); i++)  
	{
		if (cell.endian_ == "BADC") //每两个字节反序  把高八位和低八位的值反序
		{			
			if ((vec[i] & 0x00ff) == 0x0000) break;
			str.push_back(vec[i] & 0x00ff);    //提取低八位的数值
			if ((vec[i] & 0xff00) == 0x0000) break;
			str.push_back((vec[i] & 0xff00) >> 8);  //提取高八位的数值 转化为ASCII字符存到字符串中

		}
		else  //默认ABCD 大端序
		{
			if ((vec[i] & 0xff00) == 0x0000) break;
			str.push_back((vec[i] & 0xff00) >> 8);  //提取高八位的数值 转化为ASCII字符存到字符串中
			if ((vec[i] & 0x00ff) == 0x0000) break;
			str.push_back(vec[i] & 0x00ff);    //提取低八位的数值
		}
		
	}
	value = str;
	return m_statusOK;
}

bool ModbusBase::setString(const modbusCell& cell, std::string value)
{
	std::string last_str;
	getString(cell, last_str);
	std::lock_guard<std::mutex> locker(m_mutex);
	m_statusOK = true;
	size_t len = value.length();
	int it = cell.addr_;
	if (len < last_str.size())
		len = last_str.size();
	size_t count = (len + 1) / 2;
	std::map<char, std::vector <unsigned short>>* space = m_space[cell.type_];
	checkSpsce(space, cell.slave_, cell.addr_ + (count / 2) + 1);
	std::vector <unsigned short>& vec = space->at(cell.slave_);
	for (size_t i = 0; i < count; i++)
	{
		vec[it + i] = 0;
	}
	len = value.length();
	if (cell.endian_ == "BADC") //每两个字节反序  把高八位和低八位的值反序
	{
		for (size_t i = 0; i < len; i++)
		{
			unsigned short temp = 0x00ff & value.at(i++);
			if (i >= len) {  //如果是单数,例如"123"就不进行调换
				vec[it++] = temp;
			}
			else {
				temp = (temp & 0x00ff ) | ( value.at(i) << 8);
				vec[it++] = temp;
			}
		}
	}
	else  //默认ABCD 大端序
	{
		for (size_t i = 0; i < len; i++)
		{
			unsigned short temp = 0x00ff & value.at(i++);
			if (i >= len) {
				temp = temp << 8;
				vec[it++] = temp;
			}
			else {
				temp = (temp << 8) | (0x00ff & value.at(i));
				vec[it++] = temp;
			}
		}
	}
	if (m_manualFlag)
	{
		m_statusOK = manualDeal(cell, false, false);
	}
	return m_statusOK;

}


// 将十进制数转换为小端序的16进制数
QString decimalToLittleEndianHex(int decimalValue)
{
	QString hexValue = QString::number(decimalValue, 16);
	// 确保每个 16 进制数是 4 位的
	hexValue = hexValue.rightJustified(4, '0');

	// 交换字节顺序
	QString littleEndianHexValue;
	littleEndianHexValue.append(hexValue[2]);
	littleEndianHexValue.append(hexValue[3]);
	littleEndianHexValue.append(hexValue[0]);
	littleEndianHexValue.append(hexValue[1]);

	return littleEndianHexValue;
}

bool ModbusBase::getFloat(const modbusCell & cell, float & value)
{
	std::lock_guard<std::mutex> locker(m_mutex);
	m_statusOK = true;
	if (m_manualFlag)
	{
		m_statusOK = manualDeal(cell, true, false);
	}
	std::map<char, std::vector <unsigned short>>* space = m_space[cell.type_];
	checkSpsce(space, cell.slave_, cell.addr_);  

	//浮点数测试
	union IntFloatUnion {
		unsigned int intValue;
		float floatValue;
	};
	//拿取slave对应站号的地址里的十进制数据进行转换
	std::vector <unsigned short>& vec = space->at(cell.slave_); 
	QVariant v = vec[cell.addr_];
	QVariant v1 = vec[cell.addr_ + 1];
	// 将两个十进制数转换为 16 进制数
	QString hexValue1 = QString::number(vec[cell.addr_], 16);
	QString hexValue2 = QString::number(vec[cell.addr_ + 1], 16);

	// 确保每个 16 进制数是 4 位的
	hexValue1 = hexValue1.rightJustified(4, '0');
	hexValue2 = hexValue2.rightJustified(4, '0');
	// 按照大端序组合两个 16 进制数为一个 32 位的 16 进制数
	QString combinedHexValue  = hexValue1 + hexValue2;
	/*
	Big-endian               ABCD  大端序
	Big-endian Byte Swap     BADC  大端序字节反序
	Little-endian            DCBA  小端序
	Little-endian Byte Swap  CDAB  小端序字节反序
	*/
	if (cell.endian_ == "CDAB") //小端序字节反序
	{
		combinedHexValue = hexValue2 + hexValue1;
	}
	else if (cell.endian_ == "DCBA")//小端序
	{
		hexValue1 = decimalToLittleEndianHex(vec[cell.addr_]);
		hexValue2 = decimalToLittleEndianHex(vec[cell.addr_ + 1]);
		combinedHexValue = hexValue2 + hexValue1;
	}
	else if (cell.endian_ == "BADC") //大端序字节反序
	{
		hexValue1 = decimalToLittleEndianHex(vec[cell.addr_]);
		hexValue2 = decimalToLittleEndianHex(vec[cell.addr_ + 1]);
		combinedHexValue = hexValue1 + hexValue2;

	}

	// 将组合后的 16 进制数转换为整数
	bool ok;
	unsigned int intValue = combinedHexValue.toUInt(&ok, 16);
	if (ok) {
		IntFloatUnion unionValue;
		unionValue.intValue = intValue;
		float floatValue = unionValue.floatValue;  // 转换为浮点数
		// 保留三位小数
		QString formattedValue = QString::number(floatValue, 'f', 3);
		value = formattedValue.toFloat();

	}
	return m_statusOK;
}

// 将32位的浮点数拆分为两个16位的整数(大端序)
void splitBigFloatToRegisters(float floatValue, quint16& register1, quint16& register2) {
	quint32 intValue = *reinterpret_cast<quint32*>(&floatValue);
	register1 = (intValue >> 16) & 0xFFFF; 
	register2 = intValue & 0xFFFF;
}

// 将32位的浮点数拆分为两个16位的整数(小端序)
void splitLittleFloatToRegisters(float floatValue, quint16& register1, quint16& register2) {
	quint32 intValue = *reinterpret_cast<quint32*>(&floatValue);
	quint16 ts1 = (intValue >> 16) & 0xFFFF;  //转换为整数
	register1 = ((ts1 & 0xFF) << 8) | ((ts1 & 0xFF00) >> 8);  //再把整数反序
	quint16 ts2 = intValue & 0xFFFF;
	register2 = ((ts2 & 0xFF) << 8) | ((ts2 & 0xFF00) >> 8);
}

bool ModbusBase::setFloat(const modbusCell & cell, float value)
{
	std::lock_guard<std::mutex> locker(m_mutex);
	m_statusOK = true;
	std::map<char, std::vector <unsigned short>>* space = m_space[cell.type_];
	checkSpsce(space, cell.slave_, cell.addr_);
	
	if (m_manualFlag)
	{
		m_statusOK = manualDeal(cell, false, false);
	}
	/*
	Big-endian               ABCD  大端序
	Big-endian Byte Swap     BADC  大端序字节反序
	Little-endian            DCBA  小端序
	Little-endian Byte Swap  CDAB  小端序字节反序
	*/

	quint16 register1, register2;
	if (cell.endian_ == "CDAB") //小端序字节反序
	{
		splitBigFloatToRegisters(value, register1, register2);
		space->at(cell.slave_)[cell.addr_] = register2;
		space->at(cell.slave_)[cell.addr_ + 1] = register1;
	}
	else if (cell.endian_ == "DCBA")//小端序
	{
		splitLittleFloatToRegisters(value, register1, register2);
		space->at(cell.slave_)[cell.addr_] = register2;
		space->at(cell.slave_)[cell.addr_ + 1] = register1;
	}
	else if (cell.endian_ == "BADC") //大端序字节反序
	{
		splitLittleFloatToRegisters(value, register1, register2);
		space->at(cell.slave_)[cell.addr_] = register1;
		space->at(cell.slave_)[cell.addr_ + 1] = register2;

	}
	else	//默认大端序Big-endian               ABCD  大端序
	{
		splitBigFloatToRegisters(value, register1, register2);
		space->at(cell.slave_)[cell.addr_] = register1;
		space->at(cell.slave_)[cell.addr_ + 1] = register2;
	}
	

	return m_statusOK;

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值