Modebus-Rtu协议(0F)15功能码的C语言代码实现

       

        在一个远程设备中,使用15功能码强制线圈序列中的每个线圈为 ON OFF 。请求 PDU 说明了强制的线圈参考。从零开始寻址线圈。因此,寻址线圈 1 0 。 请求数据域的内容说明了被请求的 ON/OFF 状态。域比特位置中的逻辑“ 1 ”请求相应输出为 ON。域比特位置中的逻辑“ 0 ”请求相应输出为 OFF 。 正常响应返回功能码、起始地址和强制的线圈数量。
具体的代码实现如下所示:
void CMD_0F_Handle(u8 * Buf)
{
    u16 Addr = 0;
	u16 Temp = 0;    //保存输出数据
	u8 j = 0;
    TX1_Buffer[0] = Buf[0];   //发送的设备地址
    Addr = Buf[2]<<8 | Buf[3];
	Temp = Buf[8]<<8 | Buf[7];  //大小端转化
	if(Addr<=Ouput16_Register_Addres && Buf[0]==Device_Address)
	{
		 if(Addr+Buf[5]<=0x0010 && Buf[5]<=0x10 && Buf[4]==0x00 && Buf[6]!=0x00)
		{
			    TX1_Buffer[1] = Buf[1];
			    TX1_Buffer[2] = Buf[2];
			    TX1_Buffer[3] = Buf[3];
			    TX1_Buffer[4] = Buf[4];
			    TX1_Buffer[5] = Buf[5];
				for(j=0;j<Buf[5];j++)
				{
					switch(Addr+j)
					{
						case Ouput1_Register_Addres:
							{
								if((Temp&(0x0001>>Buf[3]))==(0x0001>>Buf[3]))
									Output_Value |= 0x01;
								else
									Output_Value &= 0xfe;
							}break;
						case Ouput2_Register_Addres:
							{
								if((Temp&(0x0002>>Buf[3]))==(0x0002>>Buf[3]))
									Output_Value |= 0x02;
								else
									Output_Value &= 0xfd;
							}break;
						case Ouput3_Register_Addres:
							{
								if((Temp&(0x0004>>Buf[3]))==(0x0004>>Buf[3]))
									Output_Value |= 0x04;
								else
									Output_Value &= 0xfb;
							}break;
						case Ouput4_Register_Addres:
							{
								if((Temp&(0x0008>>Buf[3]))==(0x0008>>Buf[3]))
									Output_Value |= 0x08;
								else
									Output_Value &= 0xf7;
							}break;
						case Ouput5_Register_Addres:
							{
								if((Temp&(0x0010>>Buf[3]))==(0x0010>>Buf[3]))
									Output_Value |= 0x10;
								else
									Output_Value &= 0xef;
							}break;
						case Ouput6_Register_Addres:
							{
								if((Temp&(0x0020>>Buf[3]))==(0x0020>>Buf[3]))
									Output_Value |= 0x20;
								else
									Output_Value &= 0xdf;
							}break;
						case Ouput7_Register_Addres:
							{
								if((Temp&(0x0040>>Buf[3]))==(0x0040>>Buf[3]))
									Output_Value |= 0x40;
								else
									Output_Value &= 0xbf;
							}break;
						case Ouput8_Register_Addres:
							{
								if((Temp&(0x0080>>Buf[3]))==(0x0080>>Buf[3]))
									Output_Value |= 0x80;
								else
									Output_Value &= 0x7f;
							}break;
						case Ouput9_Register_Addres:
							{
								if((Temp&(0x0100>>Buf[3]))==(0x0100>>Buf[3]))
									OutPut_Data_IO |= 0x01;
								else
									OutPut_Data_IO &= 0xfe;
							}break;
						case Ouput10_Register_Addres:
							{
								if((Temp&(0x0200>>Buf[3]))==(0x0200>>Buf[3]))
									OutPut_Data_IO |= 0x02;
								else
									OutPut_Data_IO &= 0xfd;
							}break;
						case Ouput11_Register_Addres:
							{
								if((Temp&(0x0400>>Buf[3]))==(0x0400>>Buf[3]))
									OutPut_Data_IO |= 0x04;
								else
									OutPut_Data_IO &= 0xfb;
							}break;
						case Ouput12_Register_Addres:
							{
								if((Temp&(0x0800>>Buf[3]))==(0x0800>>Buf[3]))
									OutPut_Data_IO |= 0x08;
								else
									OutPut_Data_IO &= 0xf7;
							}break;
						case Ouput13_Register_Addres:
							{
								if((Temp&(0x1000>>Buf[3]))==(0x1000>>Buf[3]))
									OutPut_Data_IO |= 0x10;
								else
									OutPut_Data_IO &= 0xef;
							}break;
						case Ouput14_Register_Addres:
							{
								if((Temp&(0x2000>>Buf[3]))==(0x2000>>Buf[3]))
									OutPut_Data_IO |= 0x20;
								else
									OutPut_Data_IO &= 0xdf;
							}break;
						case Ouput15_Register_Addres:
							{
								if((Temp&(0x4000>>Buf[3]))==(0x4000>>Buf[3]))
									OutPut_Data_IO |= 0x40;
								else
									OutPut_Data_IO &= 0xbf;
							}break;
						case Ouput16_Register_Addres:
							{
								if((Temp&(0x8000>>Buf[3]))==(0x8000>>Buf[3]))
									OutPut_Data_IO |= 0x80;
								else
									OutPut_Data_IO &= 0x7f;
							}break;							
						default:break;
					}
				}
				Output_Data(OutPut_Data_IO); //高八位
				SendTo595(Output_Value);    //低八位
				SendLegth = 6;
		}
		else
		{
			TX1_Buffer[1] = 0x8F;  //功能码最高位置1
			TX1_Buffer[2] = 0x03;	//设置异常码为03-无效数值
			SendLegth = 3;		
		}
	}
	else
	{
		TX1_Buffer[1] = 0x8F;  //功能码最高位置1
		TX1_Buffer[2] = 0x02;	//设置异常码为02-无效地址
		SendLegth = 3;			
	}
}

测试多次,非常稳定,希望对大家有帮助。 

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是一个简单的 Modbus RTU 程序示例,使用 C 语言编写: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <termios.h> #include <unistd.h> // Modbus RTU 读保持寄存器指令 int modbus_read_holding_registers(int fd, int slave_addr, int start_addr, int count, unsigned char *buf) { unsigned char request[8]; unsigned char response[255]; int i, n, len; // 构造 Modbus RTU 读保持寄存器指令 request[0] = slave_addr; request[1] = 0x03; request[2] = (start_addr >> 8) & 0xFF; request[3] = start_addr & 0xFF; request[4] = (count >> 8) & 0xFF; request[5] = count & 0xFF; len = 6; // 计算 CRC 校验码 unsigned short crc = 0xFFFF; for (i = 0; i < len; i++) { crc ^= request[i]; for (n = 0; n < 8; n++) { if (crc & 0x0001) { crc >>= 1; crc ^= 0xA001; } else { crc >>= 1; } } } request[len++] = crc & 0xFF; request[len++] = (crc >> 8) & 0xFF; // 发送指令并接收响应 int ret = write(fd, request, len); if (ret != len) { perror("write failed"); return -1; } usleep(100000); ret = read(fd, response, 255); if (ret < 0) { perror("read failed"); return -1; } // 检查响应是否正确 if (response[0] != slave_addr || response[1] != 0x03 || response[2] != count * 2) { perror("response error"); return -1; } // 处理响应数据 memcpy(buf, response + 3, count * 2); return 0; } int main(int argc, char **argv) { int fd; struct termios options; // 打开串口 fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); if (fd < 0) { perror("open failed"); return -1; } // 配置串口 tcgetattr(fd, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag |= (CLOCAL | CREAD); options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; options.c_cflag &= ~CRTSCTS; tcsetattr(fd, TCSANOW, &options); // 读保持寄存器 unsigned char buf[32]; int ret = modbus_read_holding_registers(fd, 1, 0, 16, buf); if (ret != 0) { perror("modbus read failed"); return -1; } // 打印读取结果 int i; for (i = 0; i < 16; i++) { printf("register %d: %d\n", i, buf[i]); } // 关闭串口 close(fd); return 0; } ``` 以上程序示例是一个简单的 Modbus RTU 读保持寄存器指令的实现,使用了 Linux 的串口编程接口。如果需要实现其他 Modbus RTU 指令,可以参考 Modbus RTU 协议文档进行编写。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值