jetson nano上编译与使用西门子PLC通讯库snap7

news2024/12/27 15:47:42

文章目录

  • 一.西门子snap7介绍
  • 二.西门子S7通讯介绍
  • 三.jetson nano编译snap7库
  • 四.Qt Cmake导入snap7库
  • 五.snap7主要函数说明
    • 1.与PLC建立连接
    • 2.读写PA区变量
    • 3.读写MK区变量
  • 六.通讯程序示例

一.西门子snap7介绍

Snap7 是一个基于以太网与S7系列的西门子PLC通讯的开源库。支持包括S7系列的S7-200、S7-200 Smart、S7-300、S7-400、S7-1200以及S7-1500的以太网通信。支持32/64位英特尔/ AMD的所有平台。 例如:

  • Windows ( 除了 windows Me和95);

  • Linux和类Linux(树莓派,UBeagleBone Black,DOO 等),

  • BSD;

  • Oracle Solaris ;

  • Apple OSX

支持语言也比较广:

  • Pascal;

  • C#;

  • C++;

  • C;

  • LabVIEW

  • Python;

  • Node.js

  • Java.

二.西门子S7通讯介绍

西门子S7系列PLC采用以下两种通讯方式:

  • 开放式的TCP\IP,可以用于连接PLC与其他非西门子硬件
  • 西门子自己开发的S7 Protocol以太网通讯协议,用于西门子内部硬件通讯

这两者的传输报文是不一样的,如下图:
在这里插入图片描述
西门子数存储到二进制时方式是大端模式(BIG-Endian),而我们的普通电脑常常为小端模式(Liitle-Endian)。
大端模式是指数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中.
小端模式是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
例如:双字 DWORD 0X2F11214C

PLC:
在这里插入图片描述

PC:
在这里插入图片描述

所以数据需要进行转换

三.jetson nano编译snap7库

  1. 下载源代码

    下载地址:

    https://sourceforge.net/projects/snap7/files/1.4.2/

  2. 解压下载好的文件,进入如下图所示目录
    在这里插入图片描述

  3. 空白处右键打开命令行,输入如下代码进行编译源代码以及安装

    sudo make -f arm_v6_linux.mk install
    

    在这里插入图片描述

四.Qt Cmake导入snap7库

  1. 从example/cpp文件夹中拷贝snap7.h snap7.cpp两个文件到自己的项目中
    在这里插入图片描述

  2. cmake设置如下

    cmake_minimum_required(VERSION 3.5)
    
    project(snap7Test VERSION 0.1 LANGUAGES CXX)
    
    set(CMAKE_INCLUDE_CURRENT_DIR ON)
    set(CMAKE_AUTOUIC ON)
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    find_package(QT NAMES Qt5 REQUIRED COMPONENTS Widgets)
    find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Gui)
    
    set(PROJECT_SOURCES
      main.cpp
      mainwindow.cpp
      mainwindow.h
      mainwindow.ui
      snap7.cpp
      snap7.h
    )
    
    add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
    
    target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Gui)
    target_link_libraries(${PROJECT_NAME} PRIVATE libsnap7.so)
    

    主要在下面这两个,一个是把snap7.h和snap7.cpp添加到自己的项目中,一个是添加libsnap7.so库到项目中

    
    set(PROJECT_SOURCES
      main.cpp
      mainwindow.cpp
      mainwindow.h
      mainwindow.ui
      snap7.cpp
      snap7.h
    )
    
    target_link_libraries(${PROJECT_NAME} PRIVATE libsnap7.so)
    

五.snap7主要函数说明

ConnectTo(const char *RemAddress, int Rack, int Slot);

//函数说明:通过PLC的IP地址*RemAddress建立连接。

// *RemAddress PLC的IP地址,
// Rack s7200SMART PLC的齿数,一般为0
// Slot s7200SMART PLC的槽数,一般为1
Disconnect();

//函数说明:断开PC与PLC的连接
ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData);

//函数说明:读PLC某个区域的值

//Area表示内存区。取值0x84:V区  0x83:M区  0x82:O区  0x81:I区  0x1C:C区  0x1D:T区
//DBNumber表示区域号,只有在对DB块使用时才有用,默认设置为0
//Start表示起始地址。当函数功能为读bit时,int addr =Start/8; int bit = Start%8;
// 此时表示第addr地址的第Bit位。如Start = 8;则表示第1号地址的第0位,即addr.Bit(1.0);
//Amount表示要读取的数据长度,当函数类型为读bit时,只能为1
//WordLen决定函数的功能,函数功能有读位,字节,字,双字。取值: 0x1:Bit  0x2:Byte  
// 0x4:Word  0x6:DW  0x8 : Real 0x1c : C区(16Bit)  0x1D:T区(16Bit)
//注意:读Word和DWord功能有问题,高位字节在前,低位字节在后(跟我们的程序反过来)
//*pUsrData表示数据缓冲区,读取的数据存入该缓冲区
WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void *pUsrData);

//函数说明:写PLC某个区域的值

//Area表示内存区。取值0x84:V区  0x83:M区  0x82:O区  0x81:I区  0x1C:C区  0x1D:T区
//DBNumber表示区域号,只有在对DB块使用时才有用,默认设置为0
//Start表示起始地址。当函数功能为写bit时,int addr =Start/8; int bit = Start%8;
// 此时表示第addr地址的第Bit位。如Start = 8;则表示第1号地址的第0位,即addr.Bit(1.0);
//Amount表示要写的数据长度,当函数类型为写bit时,只能为1
//WordLen决定函数的功能,函数功能有写位,字节,字,双字。取值: 0x1:Bit  0x2:Byte  
// 0x4:Word  0x6:DW  0x8 : Real 0x1c : C区(16Bit)  0x1D:T区(16Bit)
//注意:读Word和DWord功能有问题,高位字节在前,低位字节在后(跟我们的程序反过来)
//*pUsrData表示数据缓冲区,写入PLC的数据存入该缓冲区
DBRead(int DBNumber, int Start, int Size, void *pUsrData);

//函数说明:读V区的Byte值

//DBNumber读V区识别号码,只有在对DB块使用时才有用,默认设置为0
//Start读PLC的起始地址
//Size读PLC的字节个数
//*pUsrData数据缓冲区,函数读到的数据存在这个缓冲区内

DBWrite(int DBNumber, int Start, int Size, void *pUsrData);    

//函数说明:写V区的Byte值

//DBNumber读V区识别号码,只有在对DB块使用时才有用,默认设置为0
//Start读PLC的起始地址
//Size读PLC的字节个数
//*pUsrData数据缓冲区,函数读到的数据存在这个缓冲区内

//area用于区分I、Q、M、DB区域,具体选择如下
areas = ADict({
  'PE': 0x81,  #input 输入区
  'PA': 0x82,  #output 输出区
  'MK': 0x83,  #bit memory 中间存储区(M区)
  'DB': 0x84,  #DB区
  'CT': 0x1C,  #counters
  'TM': 0x1D,  #Timers
})

在这里插入图片描述
在这里插入图片描述

1.与PLC建立连接

#include "snap7.h"

TS7Client* client = new TS7Client;
char *Address = "192.168.1.10";
int Rack = 0;
int Slot = 1;
client->ConnectTo(Address, Rack, Slot);

2.读写PA区变量

int l_byData[1] = { 1 };
client->WriteArea(S7AreaPA, 0, 4, 1, S7WLBit, &l_byData); //PA区的0.4写入值1
client->ReadArea(S7AreaPA, 0, 4, 1, S7WLBit, &l_byData); //PA区的0.4读取值1

3.读写MK区变量

byte l_byData[4] = { 0 };
float l_fSpeed = 50;

//字节转换
l_byData[3] = *((byte*)&l_fSpeed + 0);
l_byData[2] = *((byte*)&l_fSpeed + 1);
l_byData[1] = *((byte*)&l_fSpeed + 2);
l_byData[0] = *((byte*)&l_fSpeed + 3);

client->WriteArea(S7AreaMK, 0, 4, 4, S7WLDWord, &l_byData); //写入值

client->ReadArea(S7AreaMK, 0, 4, 4, S7WLDWord, &l_byData); //读取值
//转换
*((byte*)&l_fSpeed + 0) = l_byData[3];
*((byte*)&l_fSpeed + 1) = l_byData[2];
*((byte*)&l_fSpeed + 2) = l_byData[1];
*((byte*)&l_fSpeed + 3) = l_byData[0];

六.通讯程序示例

# cmakeList.txt
cmake_minimum_required(VERSION 3.5)

project(snap7Test VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(QT NAMES Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Gui)

set(PROJECT_SOURCES
  main.cpp
  mainwindow.cpp
  mainwindow.h
  mainwindow.ui
  snap7.cpp
  snap7.h
)

add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})

target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Gui)
target_link_libraries(${PROJECT_NAME} PRIVATE libsnap7.so)


//main.cpp
#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "snap7.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    TS7Client* client;
    char *Address;
    int Rack = 0;
    int Slot = 1;

private slots:
    void on_ConnectpushButton_clicked();
    void on_DisconnectpushButton_clicked();
    void on_WritePApushButton_clicked();
    void on_ReadPApushButton_clicked();
    void on_WriteMKpushButton_clicked();
    void on_ReadMKpushButton_clicked();
};
#endif // MAINWINDOW_H

// mainwindow.cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"

#include <QDebug>
#include <QMessageBox>
#include "snap7.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    client = new TS7Client;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_ConnectpushButton_clicked()
{
    QByteArray ad(ui->lineEdit->text().toUtf8());
    Address = ad.data();
    Rack = ui->lineEdit_2->text().toInt();
    Slot = ui->lineEdit_3->text().toInt();
    int tmp = client->ConnectTo(Address, Rack, Slot);

    if(tmp==0)
    {
        QMessageBox::information(this,tr("success"),tr("PLC连接成功"));
    }
    else
    {
        QMessageBox::critical(this,tr("error"),tr("PLC连接失败"));
    }
}

void MainWindow::on_DisconnectpushButton_clicked()
{
    int tmp = client->Disconnect();

    if(tmp==0)
    {
        QMessageBox::information(this,tr("success"),tr("PLC断开成功"));
    }
    else
    {
        QMessageBox::critical(this,tr("error"),tr("PLC断开失败"));
    }
}

void MainWindow::on_WritePApushButton_clicked()
{
    int l_byData[1] = { ui->lineEdit_6->text().toInt() };
    int tmp = client->WriteArea(S7AreaPA, 0, ui->lineEdit_7->text().toInt(), 1, S7WLBit, &l_byData);
    if(tmp==0)
    {
        QMessageBox::information(this,tr("success"),tr("写入成功"));
    }
    else
    {
        QMessageBox::critical(this,tr("error"),tr("写入失败"));
    }
}

void MainWindow::on_ReadPApushButton_clicked()
{
    int l_byData[1] = { 0 };
    int tmp = client->ReadArea(S7AreaPA, 0, ui->lineEdit_7->text().toInt(), 1, S7WLBit, &l_byData);

    if(tmp==0)
    {
        QMessageBox::information(this,tr("success"),tr("读取成功"));

        ui->lineEdit_8->setText(QString("%1").arg(l_byData[0]));
    }
    else
    {
        QMessageBox::critical(this,tr("error"),tr("读取失败"));
    }
}

void MainWindow::on_WriteMKpushButton_clicked()
{
    byte l_byData[4] = { 0 };
    float l_fSpeed = ui->lineEdit_5->text().toFloat();

    l_byData[3] = *((byte*)&l_fSpeed + 0);
    l_byData[2] = *((byte*)&l_fSpeed + 1);
    l_byData[1] = *((byte*)&l_fSpeed + 2);
    l_byData[0] = *((byte*)&l_fSpeed + 3);

    int tmp = client->WriteArea(S7AreaMK, 0, ui->lineEdit_4->text().toInt(), 4, S7WLDWord, &l_byData);

    if(tmp==0)
    {
        QMessageBox::information(this,tr("success"),tr("写入成功"));
    }
    else
    {
        QMessageBox::critical(this,tr("error"),tr("写入失败"));
    }
}

void MainWindow::on_ReadMKpushButton_clicked()
{
    byte l_byData[20] = {0};
    float l_fSpeed = {0};
    int tmp = client->ReadArea(S7AreaMK, 0, ui->lineEdit_4->text().toInt(), 4, S7WLDWord, &l_byData);

    if(tmp==0)
    {
        QMessageBox::information(this,tr("success"),tr("读取成功"));

        *((byte*)&l_fSpeed + 0) = l_byData[3];
        *((byte*)&l_fSpeed + 1) = l_byData[2];
        *((byte*)&l_fSpeed + 2) = l_byData[1];
        *((byte*)&l_fSpeed + 3) = l_byData[0];
        ui->lineEdit_9->setText(QString("%1").arg(l_fSpeed));
    }
    else
    {
        QMessageBox::critical(this,tr("error"),tr("读取失败"));
    }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/160893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023美赛数学建模ABCDEF题思路模型代码

占个位置吧&#xff0c;开始在本帖实时更新赛题思路代码&#xff0c;文章末尾获取&#xff01; 持续为更新参考思路 赛题思路 会持续进行思路模型分析&#xff0c;下自行获取。 A题思路&#xff1a; &#xff08;比赛开始后第一时间更新&#xff09; B题思路&#xff1a;…

《算法分析与设计》复习笔记

目录 一、算法的基本概念 1.1 算法的定义 1.2 算法的“好坏”如何衡量&#xff1f; 1.3 描述算法的时间复杂度 ⭐ 1.4 如何评价算法 二、 分治法 2.1 分治法的求解步骤 2.2 平衡的概念 2.3 递归式解法 2.3.1 主定理法 ⭐ 2.4 分治法的使用条件 2.5 分治法实例 2.5…

助力安全作业生产,基于轻量级YOLOv6s开发实践反光衣检测识别分析系统

在很多实际作业生产场景中&#xff0c;出于对安全的考虑&#xff0c;施工作业等操作都是要求穿戴反光衣的&#xff0c;这个主要是为了保护人身安全&#xff0c;但是很多时候工程作业场景下因为实际种种的原因工人实际作业操作的时候很多人并没有按照要求穿戴反光衣这就给安全生…

OPTEE安全存储

本文主要介绍OPTEE的安全存储技术&#xff0c;翻译自官方文档&#xff1a;Secure storage — OP-TEE documentation documentation (optee.readthedocs.io) 一、背景 OP-TEE中的安全存储是根据GlobalPlatform的TEE Internal Core API&#xff08;这里称为可信存储&#xff09;…

2023/1/13总结

今天学习了链式向前星和唯一分解定理&#xff08;数论&#xff09;。 链式向前星 链式向前星是一种存储图的方法&#xff0c;在此之前我们学到过存储图的方式&#xff1a;邻接表以及邻接矩阵&#xff0c;邻接矩阵浪费了很大的空间&#xff0c;而邻接表 写起来的代码有一点点…

微信小程序wxml的数据和事件的绑定,以及条件和列表的渲染

文章目录1.数据绑定的基本原则在data中定义页面的数据2.事件绑定bingtap的语法格式:在事件处理函数中为data中的数据赋值事件传参bindinput的语法格式实现文本框和data之间的数据同步1.定义数据2.渲染结构3.美化样式4.绑定input事件处理函数3.条件渲染hiddenwx:if与hidden的对比…

数据库 表设计 MySQL

表设计 约束 为了保证入库数据的合理性&#xff0c;添加的各种规则。 约束的分类 准备测试用的表格&#xff1a; CREATE TABLE emp ( id INT, -- 员工id&#xff0c;主键且自增长 ename VARCHAR(50), -- 员工姓名&#xff0c;非空且唯一 joindate DATE, -- 入职日期&…

【uniapp】渲染列表数据删除项导致每项数据重置的问题解决方案

开发uniapp项目&#xff0c;使用的是JavaScript Vue写法&#xff0c;操作wList数组列表更新的时候&#xff0c;如果每一项都带input 或 radio组件&#xff0c;要操作移除的话&#xff0c;那么组件的输入数据会被清除重置&#xff0c;若不希望这样&#xff0c;那应该怎么做才好呢…

设计模式相关内容介绍—软件设计原则(六个)

在软件开发中&#xff0c;为了提高软件系统的可维护性和可复用性&#xff0c;增加软件的可扩展性和灵活性&#xff0c;程员要尽量根据6条原则来开发程序&#xff0c;从而提高软件开发效率、节约软件开发成本和维护成本。 目录 1.开闭原则 2.里氏代替原则 3.依赖倒转原则 4.接…

dvwa中的文件包含攻击

环境&#xff1a;dvwa: 192.168.11.135 dvwa版本&#xff1a; Version 1.9 (Release date: 2015-09-19)kail机器&#xff1a;192.168.11.156一、什么是文件包含漏洞?为简化代码&#xff0c;会把重复的code内容单独写到一个页面文件&#xff0c;然后再需要调用重复内容的页面中…

C语言:初识C语言

目录前言1. 什么是c语言呢2. 第一个c语言程序2. 数据类型3. 变量和常量3.1 变量3.1.1 变量的定义3.1.2 变量的分类3.1.3 变量的使用3.1.4 变量的作用域和生命周期3.2 常量4. 字符串、转义字符、注释4.1 字符串4.2 转义字符4.3 注释5. 选择语句6. 循环语句7. 函数8. 数组9. 操作…

学习笔记——keep-alive缓存组件,再次返回组件data数据重置

前言&#xff1a;使用keep-alive缓存组件&#xff0c;当再次返回该组件后&#xff0c;希望其组件中的数据或状态&#xff0c;保持上次离开该组件时的情况。 一、当前组件树 希望缓存HomeMain组件的状态。 二、错误处理 我在HomeMain的祖先组件HomeLayout中&#xff0c;写了如下…

sqlplus 连接数据库

终端直连 Oracle 数据库 ORA-12162 错误 出于各种网络原因&#xff0c;无法直连数据库&#xff0c;但又必须查询数据库数据 我们只能选择直连数据库的服务器 然后通过 sqlplus 连接 Oracle 从配置文件里获取这样一段信息 urljdbc:oracle:thin:192.168.1.3:1521:testdb use…

【SpringCloud08】SpringCloud Consul服务注册与发现

1.Consul简介 1.1是什么 官网 Consul 是一套开源的分布式服务发现和配置管理系统&#xff0c;由 HashiCorp 公司用Go 语言开发 提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用&#xff0c;也可以一起使用以构建全方位…

基于MPLS-V**多分部互访的ensp企业网络规划与设计_ensp综合实验

作者&#xff1a;BSXY_19计科_陈永跃BSXY_信息学院注&#xff1a;未经允许禁止转发任何内容基于MPLS-V**多分部互访的ensp企业网络规划与设计_ensp综合实验前言及技术/资源下载说明&#xff08; **未经允许禁止转发任何内容** &#xff09;插曲&#xff1a;基于eNSP中大型校园/…

卡特加特数字中控主机,数字家庭控制中心!没它智能家居就是智障!

数字中控主机是数字家庭的核心&#xff0c;承担着“协调各方、总揽全局”的作用&#xff0c;是打造未来数字家庭空间必不可少的设备。区别于传统家居智能&#xff0c;它真正意义上告别了过去以设备为中心的架构&#xff0c;而是以人的个性化需求为中心&#xff0c;以数据作为资…

2020统考真题-距离最小三元组

2020年统考真题 定义三元组$ (a,b,c)$ &#xff08; a,b,c 均为正数&#xff09;的距离 D∣a−b∣∣b−c∣∣c−a∣D|a−b||b−c||c−a|D∣a−b∣∣b−c∣∣c−a∣ 。给定 3个非空整数集合 S1 、 S2 和 S3 &#xff0c;按升序分别存储在 3 个数组中。请设计一个尽可能高效的算…

蓝队攻击的四个阶段(三)

目录 一&#xff0c; 专业技能储备 1.工具开发技能 2.漏洞挖掘技能 3.代码调试技能 4.侦破拓展技能 二&#xff0c;目标网情搜集 1 何为网情搜集 2. 网情搜集的主要工作 三&#xff0c; 网情搜集的途径 1.专业网站 2.专业开发资源网站 3.目标官网 一&#xff0c; 专…

算法训练营 day17 二叉树 平衡二叉树 二叉树的所以路径 左叶子之和

算法训练营 day17 二叉树 平衡二叉树 二叉树的所以路径 左叶子之和 平衡二叉树 110. 平衡二叉树 - 力扣&#xff08;LeetCode&#xff09; 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每…

osg fbo(五) 通过shader计算纹理坐标并采样

在前边几节&#xff0c;纹理坐标数组是在生成geometry前指定的。 这里在shader里计算&#xff0c; 一&#xff0c;注释掉geometry中的纹理坐标 //osg::ref_ptr<osg::Vec2Array> texCoord new osg::Vec2Array; //texCoord->push_back(osg::Vec2(0.0, 0.0)); //texCoo…