基于Modbus协议实现远程控制和数据检测

项目基本情况:

远程对工业现场的设备进行开关控制和实时数据采集,基于modbus tcp协议,和webserver服务器,实现客户在网页进行获取设备的传感器数据和控制设备上的开关;

基本流程:网页通过web服务器对设备发送指令:如果是收集数据:因为设备通过modbus协议不断的将即时数据发送到服务器,当服务器获取到网页端的请求是获取传感器数据时就把设备的通过http协议发送给网页,客户就可以即时查看设备数据了,如果是控制设备,在网页上输入控制命令,服务器通过modbus协议格式对设备进行控制开关。

起源:

Modbus由Modicon公司于1979年开发,是一种工业现场总线协议标准。

Modbus通信协议具有多个变种,其中有支持串口,以太网多个版本,其中最著名的是Modbus RTUModbus ASCII和Modbus TCP三种

分类:

1) Modbus RTU: 运行在串口上的协议,采用二进制表现形式以及紧凑型数据结构,通信效率高,应用广泛

2) Modbus ASCII: 运行在串口上的协议,采用ASCII码传输,并且利用特殊字符作为其字节的开始与结束标识,其传输效率要远远低于Modbus RTU协议,一般只有在通信数据量较小的情况下才考虑使用Modbus ASCII通信协议

3) Modbus TCP: 运行在以太网上的协议

为什么要使用modbus协议?

Modbus协议是现在国内工业领域应用最多协议,不只PLC设备,各种终端设备,比如水控机、水表、电表、工业秤、各种采集设备

优势免费、简单、容易使用

Modbus TCP特点:(本项目使用的是modbus tcp协议)

Modbus TCP:运行在以太网上的协议:

1) 采用主机和从机之间问答方式进行通信

2) Modbus TCP是应用层协议,基于传输层TCP协议实现

3) Modbus TCP端口号默认为502

任务:

编程实现采集传感器数据和控制硬件设备(传感器和硬件通过slave模拟)

传感器:2个,光线传感器、加速度传感器(x\y\z)

硬件设备:2个,led灯、蜂鸣器

要求:

1. 多任务编程:多线程、多进程

2. 循环1s采集一次数据,并将数据打印至终端

3. 同时从终端输入指令控制硬件设备

0 1 :led灯打开

0 0:led灯关闭

1 1:蜂鸣器开

1 0 : 蜂鸣器关

编程流程

1. 创建实例

modbus_new_tcp

2. 设置从机ID

modbus_set_slave

3. 和从机进行连接

modbus_connect

4. 寄存器进行操作

功能码对应函数

5. 关闭套接字

modbus_close

6. 释放实例

modbus_free

#include <stdio.h>
#include <stdlib.h>
#include <modbus-tcp.h>
#include <modbus.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <errno.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

void *handler(void *arg);    //子线程
int create_shimd(char *buf); //创建共享内存

modbus_t *ctx = NULL;    //定义modbus类型的 指针ctx;
uint16_t dest[64] = {0}; //定义数组 接收从机的回答;
uint8_t data[64] = {0};  //定义数组 接收从机的回答;
int addr, status;

key_t key; //创建key值

int main(int argc, char const *argv[])
{

  if (argc != 3)
  {
    printf("please input%s<ip> <port>\n", argv[0]);
    return -1;
  }
  key = ftok("/home/hq/app.c", 'b');
  if (key < 0)
  {
    perror("ftok err");
    return -1;
  }

  //1.以tcp方式创建modbus实例,并初始化
  ctx = modbus_new_tcp(argv[1], atoi(argv[2]));
  if (ctx != NULL)
  {
    printf("modbus_new_tcp ok\n");
  }
  else
  {
    printf("modbus_new_tcp err\n");
    return -1;
  }

  //2.设置从机ID
  modbus_set_slave(ctx, 1);

  //3.和从机(slave)建立连接
  modbus_connect(ctx);

  //创建一个线程
  pthread_t tid;
  pthread_create(&tid, NULL, handler, NULL);
  pthread_detach(tid);
  while (1) //主线程
  {
    //创建消息队列
    struct msgbuf
    {
      long type; //暗号 ,另外的程序必须用同样type值才能接收
      int a;
      int b;
      char c[128];
    };
    struct msgbuf msg; //定义结构体变量
    int msgid;
    msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
    if (msgid < 0)
    {
      if (errno == EEXIST)
        msgid = msgget(key, 06666);
      else
      {
        perror("msgget err");
        return -1;
      }
    }               
    size_t s = sizeof(msg) - sizeof(long);               
    msgrcv(msgid, &msg, s, 0, 0); //第四个参数0:读取消息队列中第一个消息
    //写入多个连续线圈的状态
    //printf("(数字之间用1个空格隔开):\n0 1(led灯打开),0 0(led灯关闭),1 1(蜂鸣器开),1 0(蜂鸣器关)\n请输入:");
    // int num = scanf("%d %d", &addr, &status);
    modbus_write_bit(ctx, msg.a, msg.b);
    modbus_read_bits(ctx, msg.a, 1, data); //读多个线圈//此时读一个
    if (msg.a == 0)
      sprintf(msg.c,"led灯的状态为:(1开,0关):%d\n\n", data[0]);
    else if (msg.a == 1)
    {
      sprintf(msg.c,"蜂鸣器的状态为:(1开,0关):%d\n\n", data[0]);
    }

      msgsnd(msgid, &msg, s, 0);//0 阻塞 把控制后的数据发回浏览器
  }
  // pthread_join(tid,NULL);//阻塞,等待子线程结束后回收子线程资源后不阻塞 主线程才能执行剩余代码退出
  modbus_close(ctx); //关闭套接字,先关闭,后释放(因为sockfd保存在实例空间里,先释放就不知道sockfd描述符是什么了)
  modbus_free(ctx);  //释放modbus实例

  return 0;
}

void *handler(void *arg) //子线程
{

  while (1)
  {
    //读取003H保持寄存器的值,可读取多个连续保持寄存器的值
    int ret = modbus_read_registers(ctx, 0, 4, dest);
    printf("成功读取到%d个保持寄存器数据\n", ret);
    printf("光线:%#04x 加速度x:%#04x 加速度y:%#04x 加速度z:%#04x",
           dest[0], dest[1], dest[2], dest[3]);
    printf("\n");
    char buf[128];
    sprintf(buf, "光线:%#04x 加速度x:%#04x 加速度y:%#04x 加速度z:%#04x",
            dest[0], dest[1], dest[2], dest[3]);
    create_shimd(buf);
    sleep(5);
  }
  pthread_exit(NULL);
}
int create_shimd(char *buf) //创建共享内存
{
  //1.2创建共享内存
  int shmid;
  shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666);
  if (shmid < 0)
  {
    if (errno == EEXIST)
      shmid = shmget(key, 128, 0666);
    else
    {
      perror("shmget err");
      return -1;
    }
  }
  char *m = NULL;
  //映射共享内存
  m = (char *)shmat(shmid, NULL, 0);
  //读取共享内存的数据
  strcpy(m, buf);
  return 0;
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Modbus TCP是一种专为工业控制和自动化应用设计的通信协议,它为工厂自动化网络中的设备和控制节点之间提供了可靠的双向数据传输。它基于TCP/IP协议,将Modbus功能添加到一个已经存在的网络中,使其具有可靠的数据传输功能,从而使远程控制和监控变得更加容易。Modbus TCP协议支持设备之间的通信,也支持与设备之间的控制和监视,它支持点对点通信和广播通信,它的实施简单,跨越多种网络架构,功能强大。 ### 回答2: Modbus TCP协议是一种用于工业自动化系统中的通讯协议Modbus是一种基于从属/主控设备通信的开放通讯协议,旨在简化工业控制系统之间的通信。它通过标准化数据格式和规范的通讯规则,实现了不同设备之间的信息交换。 Modbus TCP协议是基于TCP/IP协议Modbus协议的变体。它将Modbus通讯协议封装在TCP/IP的数据包中进行传输。通过使用以太网或WiFi等网络连接,Modbus TCP协议可以实现在不同设备之间的高速数据通信。 Modbus TCP协议涉及到两个主要角色:Modbus TCP主控设备和Modbus TCP从属设备。主控设备负责发送指令和请求数据,而从属设备则负责响应这些指令并提供所需的数据Modbus TCP协议中的数据通信是基于客户端-服务器的模型。主控设备作为客户端发送请求,从属设备则作为服务器进行响应。主控设备通过建立TCP连接向从属设备发送读取或写入数据的指令,从属设备通过响应数据帧回复所需要的数据Modbus TCP协议数据帧结构通常包括一个设备地址、功能码、数据字段和错误校验字段。设备地址用于标识从属设备,功能码指示主控设备请求的类型(例如读取数据、写入数据等)。数据字段包括需要传输的数据,错误校验字段用于检测数据传输的准确性。 使用Modbus TCP协议有许多优势。首先,它支持在广域网上进行远程访问,使得实时监控和控制变得更加方便。其次,它具有较高的可扩展性和灵活性,可以轻松添加或删除设备。此外,Modbus TCP协议还具有较低的成本和简单的实施。 总之,Modbus TCP协议是一种广泛使用的工业自动化通讯协议,它提供了高效可靠的设备之间的数据传输和通信,有助于实现工业控制系统的互联互通。 ### 回答3: Modbus TCP协议是一种用于工业自动化系统中的通信协议,它是基于TCP/IP协议Modbus协议的一种实现方式。 Modbus TCP协议通过以太网进行通信,使用TCP/IP协议栈来传输Modbus协议数据。它适用于各种不同的设备,如传感器、执行器、PLC等,可以实现不同设备之间的数据交换和控制。 Modbus TCP协议的通信方式是以主从结构进行通信。主设备负责发送请求指令,从设备收到请求后执行相应的动作并返回响应数据。主设备可以同时与多个从设备进行通信。 Modbus TCP协议数据传输格式基于Modbus协议,包含了一些常用的功能码,如读取寄存器、写入寄存器、读取输入寄存器等。这些功能码用于对设备进行读写操作,实现数据的采集和控制。 Modbus TCP协议的优点是可靠性高、实时性强、网络拓扑灵活。通过使用TCP/IP协议栈,可以在广域网和局域网中进行通信,并且可以通过网络中的路由器和交换机实现设备的远程访问。由于它在工业自动化领域得到了广泛的应用和支持,Modbus TCP协议的设备和软件非常丰富。 总结来说,Modbus TCP协议是一种基于TCP/IP协议Modbus协议实现方式,用于工业自动化系统中的设备通信和控制。它具有可靠性高、实时性强、灵活的网络拓扑等优点,广泛应用于各种工业设备和系统中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值