Advanced network -- the use of tool software

Table of contents

Modbus Slave  &  Poll

 Network debugging assistant

Wireshark uses

Exercise: Implement the poll function to communicate with the slave


Modbus Slave  &  Poll

1. Download the software and install it by default

2. Crack, click connection->connect, enter the serial number

3. use

set first

 Then connect ( note that the Slave end is turned on first, and the Poll end is turned on later )

 View host ip address

win+R key, enter ipconfig

 

 

 Network debugging assistant

Note that the protocol is sent correctly, note that the register type must match, connect first and then send

 

Wireshark uses

Capture selection:

If windows is connected to a wired network, select Local Area Connection/Ethernet

If connected to a wireless network, select WLAN

If it is only communication on this machine, choose NPCAP Loopback apdater

filter criteria:

Filter port: tcp.port == 502

Filter ip address: ip.addr == 192.168.xx.xx (set according to your own ip address under Windows)

Exercise: Implement the poll function to communicate with the slave

Encapsulate the function separately to realize the reading of the holding register and the control of a single coil

Read holding registers: function parameters (register start address, number of registers, slave ID)

#include <stdio.h>
#include <stdlib.h> // atoi
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>

int sockfd; //定义文件描述符
void set_slave_id(uint8_t *p, int id) //设置从机id
{
    *(p + 6) = id;
}
//读保持寄存器      (发送数据首地址,  功能码,   寄存器地址,寄存器数量,存放接受数据首地址)
void read_registers(uint8_t *p, int function, int addr, int nb, uint8_t *dest)
{
    int i;
    *(p + 5) = 6;              //后面字节数
    *(p + 7) = (char)function; //功能码
    *(p + 8) = addr >> 8;      //寄存器高字节地址
    *(p + 9) = addr & 0xff;    //寄存器低字节地址
    *(p + 10) = nb >> 8;       //寄存器数量高位
    *(p + 11) = nb & 0xff;     //寄存器数量低位
   
/*
           1101 0101 1010 1001
  addr>>8  0000 0000 1101 0101  高字节地址

  addr&0xff 1101 0101 1010 1001
          & 0000 0000 1111 1111
          = 0000 0000 1010 1001 低字节地址

 */
    send(sockfd, p,12,0);//注意这里不能sizeof(p),p为指针
   
    recv(sockfd, dest,64,0);//注意这里不能sizeof(dest),dest为指针
}

void write_coil(uint8_t *p, int function, int addr, int nb, uint8_t *dest)
{
    int i = 0;
    *(p + 5) = 6;              //后面字节数
    *(p + 7) = (char)function; //功能码
    *(p + 8) = addr >> 8;      //线圈高位地址
    *(p + 9) = addr & 0xff;    //线圈低位地址
    if (nb == 1)
        *(p + 10) = 0xff;
    else if (nb == 0)
        *(p + 10) = 0x00;
    *(p + 11) = 0x00;

    send(sockfd, p, 12, 0);
    recv(sockfd, dest, 64, 0);
}

int main(int argc, char const *argv[])
{
    struct sockaddr_in s;

    uint8_t data[12] = {0};
    uint8_t dest[64] = {0};
    int i;

    //1.socket创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    socklen_t len = sizeof(struct sockaddr_in);
    //2.填充结构体
    s.sin_family = AF_INET;                 //协议族
    s.sin_port = htons(atoi(argv[2]));      // htons:小端转大端 atoi:将数字字符串转换为数值
    s.sin_addr.s_addr = inet_addr(argv[1]); //字符串转点分十进制

    //3.connect请求连接
    if (connect(sockfd, (struct sockaddr *)&s, len) < 0)
    {
        perror("connect err");
        return -1;
    }
    //4.设置从机ID
    set_slave_id(data, 1);

    //5.循环发送
    while (1)
    {
        printf("开始读\n");
        read_registers(data, 0x03, 0, 2, dest);
        printf("recv data:");
        for (i = 0; i < dest[8]; i++)
            printf("%d  ", dest[9 + i]);
        printf("\n");
        sleep(5);
        write_coil(data,0x05,0,1,dest);//线圈置一
        printf("线圈置位后:\n");
        printf("%d  %d  \n",dest[10],dest[11]);
        sleep(5);
    }

    //5.关闭套接字
    close(sockfd);
    return 0;
}

operation result

 

Guess you like

Origin blog.csdn.net/m0_68672255/article/details/130411425