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

一.西门子snap7介绍

官网:https://snap7.sourceforge.net/

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];

六.通讯程序示例

打包下载地址:https://download.csdn.net/download/qq_30150579/87382222

# 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("读取失败"));
    }
}

在这里插入图片描述

### 回答1: 如果你想在Jetson Nano上编译Qt,你可以按照以下步骤操作: 1. 安装所需的依赖项: ``` sudo apt-get update sudo apt-get install build-essential libfontconfig1-dev libdbus-1-dev libfreetype6-dev libicu-dev libinput-dev libxkbcommon-dev libsqlite3-dev libssl-dev libpng-dev libjpeg-dev libglib2.0-dev libgles2-mesa-dev libglu1-mesa-dev libgl1-mesa-dev ``` 2. 下载Qt源代码: 你可以从Qt官网下载Qt源代码,或者使用以下命令: ``` wget http://download.qt.io/official_releases/qt/5.15/5.15.0/single/qt-everywhere-src-5.15.0.tar.xz ``` 3. 解压源代码: ``` tar xf qt-everywhere-src-5.15.0.tar.xz ``` 4. 配置编译选项: ``` cd qt-everywhere-src-5.15.0 ./configure -release -opengl es2 -device linux-jetson-nano-g++ -device-option CROSS_COMPILE=aarch64-linux-gnu- -sysroot /usr/aarch64-linux-gnu/ -prefix /usr/local/qt5 ``` 5. 开始编译: ``` make -j4 ``` 6. 安装Qt: ``` sudo make install ``` 请注意,编译Qt可能需要很长时间,请耐心等待。 ### 回答2: Jetson Nano是一款强大的开发板,可以用来开发和部署各种人工智能和计算机视觉项目。编译Qt是在Jetson Nano上构建Qt开发环境的过程,下面是编译Qt的步骤: 1. 准备Jetson Nano开发板:确保您已正确设置Jetson Nano的软件和硬件环境,并连接到网络。 2. 下载Qt源代码:在Jetson Nano上下载Qt的源代码,您可以选择从Qt官方网站下载最新版本的源代码。 3. 安装依赖项:在Jetson Nano上安装所需的依赖项,包括编译工具链、开发和其他必需的软件包。要安装这些依赖项,可以使用包管理器,如apt-get。 4. 配置Qt编译:在Jetson Nano上配置Qt的编译选项。您可以使用configure命令配置您需要的模块、功能和其他参数。 5. 开始编译:运行make命令开始编译Qt。这个过程可能需要一段时间,具体时间取决于您的硬件性能和编译选项。 6. 安装Qt:在编译完成后,运行make install命令将编译好的Qt安装到您的Jetson Nano上。 7. 测试Qt:编译和安装完成后,您可以运行一些Qt示例来验证Qt是否正常工作。 以上是在Jetson Nano上编译Qt的基本步骤。您可以根据您的需求和环境进行定制化设置和调整。请注意,编译Qt可能需要较长的时间和较高的系统资源,建议在Jetson Nano上进行编译时保持足够的空间和电源。 ### 回答3: 编译Qt软件包到Jetson Nano包括以下几个步骤: 1. 首先,在Jetson Nano上安装必要的开发工具。您可以使用以下命令安装所需的软件包: ``` sudo apt-get update sudo apt-get install build-essential sudo apt-get install qt5-default ``` 2. 下载Qt源代码包。您可以从Qt官方网站下载最新的Qt源代码包,并解压缩到您选择的目录中。 3. 创建一个构建目录。在解压缩的Qt源代码目录的根目录中创建一个新的目录,并进入该目录: ``` cd <解压后的Qt源代码目录> mkdir build cd build ``` 4. 配置Qt编译选项。在构建目录中,运行`qmake`命令,配置Qt的编译选项。根据您的需求,您可以在命令中添加各种选项,例如指定Qt模块、编译工具链等。 ``` qmake <路径/到/Qt源代码目录> ``` 5. 编译Qt。在构建目录中,运行`make`命令,开始编译Qt。这将花费一些时间,取决于您的Jetson Nano的性能。 ``` make ``` 6. 安装Qt。编译完成后,运行以下命令安装Qt到默认位置(/usr/local/qt5): ``` sudo make install ``` 7. 配置环境变量。为了能够正确使用安装的Qt,您需要将Qt的bin目录添加到系统的PATH环境变量中。在终端中运行以下命令来编辑`~/.bashrc`文件: ``` nano ~/.bashrc ``` 在文件的末尾添加以下行,并保存文件: ``` export PATH=/usr/local/qt5/bin:$PATH ``` 然后运行以下命令使环境变量生效: ``` source ~/.bashrc ``` 现在,您已经成功地编译并安装了Qt。您可以使用Qt Creator或其他开发环境来开发和构建Qt应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AoDeLuo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值