@@@ 实战高级语言直接访问S7-200 [ 一 ] 点击:1066 | 回复:7



尐お槑孨/叶宏

    
  • 精华:3帖
  • 求助:0帖
  • 帖子:114帖 | 3593回
  • 年度积分:0
  • 历史总积分:7688
  • 注册:2008年3月16日
发表于:2012-06-30 09:28:11
楼主

我有一只S7-200 226PLC及三根不同的连接线,以前用PC ACCESS的OPC方式可以实现用电脑,访问它,总觉得太烦,很想试试电脑直接用对话协议访问。

 

非广告!

 

西门子的原配连接线,串口,价贵500元,是我去南京的西门子代理那里买的,可以以极高的速度通迅。由于本子上并没有串口,只在台式上用。

这是串口简易线,扬州可以买到,100元,但只能以普通速度通迅,本子上也不好用。

这是国内生产的仿制连接线,一头是USB口,可以用在本子上,这是我常用的一根线了,

需要安装驱动程序,因为它以USB仿真串口的方式,本子上插上线后,就可在硬件管理器

上找到所仿真的串口号,可以修改对应串口号。这要查一下,不知串口号是无法通迅的。




尐お槑孨/叶宏

  • 精华:3帖
  • 求助:0帖
  • 帖子:114帖 | 3593回
  • 年度积分:0
  • 历史总积分:7688
  • 注册:2008年3月16日
发表于:2012-06-30 09:29:00
1楼

PPI对话协议前几年网上就有文章,但说的很含糊没法用高级语言实施,这几年文章多了,百度上可以搜到,

已说的很清楚了,我总结了一下,对每一个字节进行分析,几乎差不多明白了:

S7-200 PPI通讯协议

 

一、读PLC的报文一次一组最多读222字节的数据

一般33字节,编号从032,由三部分组成:头块、命令块、尾块

(1) 头块  【4B】

0. SD   头标志68H

1. LE   命令块字节数 读为1B,即27字节;

2. LER  同上, 冗余的

3. SD   头标志68H

(2)   命令块 【27B】

4. DA   目的地址:    PLC地址默认2】

5. SA   源地址:      PC地址  00

6. FC   命令码        6C/7C

7-12.DSAP 目的存取点    320100000000 

  13.SSAP 源存取点      00 

14.SSAP 数据块长      0E, 公式:  4+块数*10  (一组)      

15-18. SSAP               00000401

19-21. BK   命令头        120A10         

   22.      单元类型      1:1/2:字节/4:/6:双字

   23.      保留          00

   24.      单元数        位:1,    NN个单元

   25.      保留          00

   26.      是否V      1:V/0:非V

   27.      单元类型       04:S/05:SM/06:AI/07:AQ/1E:C/

                          81:I/82:Q/83:M/84:V/T:1F

28-30.   单元按位编址      地址*8+位址,   28/29/30由高位到低位

(3) 尾块  【2B】

   31. FCS  命令块字节和  27字节的和为校验码

   32. ED   尾标志        16H    

 

注:PC发送后,PLC将返回E5,等待几个毫秒后电脑再发送10  2  0  5C  5E  16后,将发回应答数据块。应答块的长度与要求的数据字节有关,位或1字节为28字节(1BH),单字读取为29字节,双字读取为31字节。

PLC读取后的返回块格式:

00 – 20  不要关心

    21  FF

    22  03/非位04

    23  读取的总位数高位

    24  读取的总位数低位  :1,字节:8,:10H,双字:20H

    25  读到的数据开始, N14个字节

 25+N   命令块的校验和(不包括头块与尾块)

 26+N   尾标志16H  

 

二、PLC的报文  每次只能写1个单元,不超过4字节

由三部分组成:头块、命令块、尾块  总长度与写入数据的字节数有关,写1字节为20H,二字节为21H,双字为23H

 

(1) 头块  【4B】

0. SD   头标志68H

1. LE   命令块字节数   20H23H

2. LER  同上, 冗余的

3. SD   头标志68H

(2)   命令块 【20H-23H】

4. DA   目的地址:    PLC地址默认2】

5. SA   源地址:      PC地址  00

6. FC   命令码        7C/6C

7-12.DSAP 目的存取点    320100000000 

  13.SSAP 源存取点      00 

14.SSAP 数据块长      0E,        

15                    00   

16 GU4                5/字节5/6/双字 8

17-18                     0501

19-21. BK   命令头        120A10         

   22.      单元类型      1:1/2:字节/4:/6:双字

   23.      保留          00

   24.      写字节数      位:1/ NN个单元

   25.      保留          00

   26.      是否V      1:V/0:非V

   27.      单元类型      04:S/05:SM/06:AI/07:AQ/1E:C/

                          81:I/82:Q/83:M/84:V/T:1F

28-30.   单元按位编址      地址*8, 28/29/30由高到低

   31       保留          00

   32       是否位        03:/04: 非位

33       总位数     读取的总位数高位

34       总位数     :1/字节:8/:10H/双字:20H

35   写入的数据        字节为N =1 

(3) 尾块  【2B】

 35+N.      FCS  命令块字节和做校验码

 36+N.      ED   尾标志 16H    

 

注:PC发送后,PLC将返回E5,等待几个毫秒后电脑再发送10  2  0  5C  5E  16后,将发回应答数据块。应答块的长度固定24字节

 

写入PLC后的返回块格式,可以不关心。

 

中国第一“小萝莉” 西子小小萌照

尐お槑孨/叶宏

  • 精华:3帖
  • 求助:0帖
  • 帖子:114帖 | 3593回
  • 年度积分:0
  • 历史总积分:7688
  • 注册:2008年3月16日
发表于:2012-06-30 09:29:46
2楼

工控人一般用VB工具编程较多,少数高校的“高手”喜欢用VC,我认为:

1.VB编程简单,易入门,但是解释执行,运行速度并不快,但它是可视化编程工具,多数人很喜欢它;

2. DELPHI与C++BUILDER 是姐妹语言工具,编译执行,比VB执行快多了,也是可视化的,我认为这是

   最佳的编程工具,DELPHI学生用的多,C++BUILDER用的人不太多,但我喜欢用,是C++是可视化最

   好的编程工具,数据库支持的非常好;

3. 微软的VC++可视化程度低,编程太烦,开发效率太低,比C++BUILDER的技术要低一代,但高校人

   认为VC++是时髦高档工具,很少知道C++BUILDER更方便。

所以,我认为 C++BUILDER/DELPHI是首选语言,其次是VB很方便;最后VC++是最差的。

90后女友

尐お槑孨/叶宏

  • 精华:3帖
  • 求助:0帖
  • 帖子:114帖 | 3593回
  • 年度积分:0
  • 历史总积分:7688
  • 注册:2008年3月16日
发表于:2012-06-30 09:30:07
3楼

因为用的是串行通迅,需要有现成的模块,

最方便的还是微软的串口控件 MSCOMM32.ocx, 有一部分人认为它有问题,其实是因为没掌握它的方法,

多数人认为它不方便发布,需要注册,不便于做绿色EXE程序, 其实MSCOMM32.ocx 可以资源方式绑入

EXE,  执行时释放到windows 系统目录中,再用动态DLL的方式自注册(mscomm32.ocx自带有注册子程序):

                 delphi 中tmscomm控件使用指南

Delphi 中TMsComm控件使用指南
l 注册TMsComm控件


1.将Mscomm.srg, Mscomm32.ocx,Mscomm32.dep三个文件复制到系统文件夹中C:\winnt\system32\。

2.用Windows下的注册工具regsvr32注册该OCX控件,点击“开始”->"运行",再在中填入(假设操作安装在C盘,WIN2000):

Regsvr32 C:\winnt\system32\Mscomm32.ocx

3.在注册表中手工新建一个主键项:先在点击“开始”->"运行",再在中填入regedit命令打开注册表,找到HKEY_CLASSES_ROOT\Licenses,在其中添加主键

4250E830-6AC2-11cf-8ADB-00AA00C00905 并将内容设置为:

kjljvjjjoquqmjjjvpqqkqmqykypoqjquoun

l 引入TMSComm控件


(1)进入Delphi 编程环境下,在菜单项中选中Component/Import ActiveX选项,出现ActiveX控件导入窗口;

(2)在其中选中Microsoft Comm Control 6.0(Version 1.1),并按需要选定Palette pages、unit dir name、Search path值(一般取默认值),最后选择Install按钮进行安装。即可将MSComm控件引入到Delphi 中。

(3)在编程使用中,直接打开ActiveX控件,选取TMSComm控件,放在窗体上,设置其属性即可。其使用方法与Delphi其它控件相同.


l TMSComm控件的主要属性及事件


MSComm控件有27个属性,其中一部分可缺省设置为不用,常用的属性如下:

(1) CommPort:设置串行口选择。缺省值为1,选择为COM1;若赋值为2,则选择COM2。

(2) PortOpen:设置通信端的状态。设置为True时,打开端口;设置为False时,关闭端口并清除接受和发送缓冲区。

(3) Settings:设置通信时的波特率、奇偶校验、停止位参数。

(4) Inputlen:设置每次从接受缓冲区读却的字符个数。缺省值为0,表示将读取接受缓冲区中全部内容;若设置值为n,表示每次将读取接受缓冲区中的n个字符。

(5) InputMode:设置接收数据的类型。

(6) InBufferCount:设置返回接受缓冲区中等待被读取的字符个数。初始化程序时,InBufferCount设置值为0,表示清除接受缓冲区。

(7) OutBufferCount:设置返回发送缓冲区中等待发送的字符个数。设置值为0时,表示清除发送缓冲区。

(8) InBufferSize:设置接受缓冲区中的长度,缺省值为1024字节。

(9) OutBufferSize:设置发送缓冲区中的长度,缺省值为512字节。

(10) Rthreshold:设置表示在触发OnComm事件之前接收缓冲区允许有的字符数。缺省值为0,表示即使接收缓冲区有字符时,也不会触发OnComm事件;设置值为n时,表示接收缓冲区每有n个字符时,就会触发一次OnComm事件。

(11) Sthreshold:设置表示在触发OnComm事件之前发送缓冲区允许有的字符数。缺省值为0,表示不触发OnComm事件;设置值为n时,表示发送缓冲区每有n个字符时,就会触发一次OnComm事件。

(12) DTREnable:设置DTR的有效性。

(13) RTSEnable:设置RTS的有效性。

(14) Input:从串口读取数据。

(15) Output:向串口写入数据。

 

尐お槑孨/叶宏

  • 精华:3帖
  • 求助:0帖
  • 帖子:114帖 | 3593回
  • 年度积分:0
  • 历史总积分:7688
  • 注册:2008年3月16日
发表于:2012-06-30 09:30:26
4楼

使用MSCOMM32.ocx 多数人使用它的异步方式,就是事件方式,但我认为与PLC通迅还是用同步方式方便,

就是说发送命令串后,立即用读取语句读取到应答串,程序更简单。

你只要编两个子程序就完全可以了:

1 。发送子程序  void    PPI::SendBuf(BYTE buf【】,int size)  // 向串口发送size字节

2.   读取子程序   int    PPI::ReadBuf(BYTE *buf,int &size,int tk)

         // 从串口读size个字节,size=0表示读所有字节,超时值 tk 毫秒

        //  返回出错状态

有了这两个子程序,一切就简单了,VB同样可以编出这两个子程序:

//---------------TMSCOMM---------------------------------
int    PPI::ReadBuf(BYTE *buf,int &size,int tk)
{       // 从串口读size个字节,size=0表示读所有字节,超时值tk
       int err=0;    // 0:正常,1:端口关,2:超时, 3:字符满
       int count=0;
       OleVariant vbuf;
       int   tk0=GetTickcount();
       while (err==0)
        {
               if (!MSComm->PortOpen)
                 {  err=1;
                    break;
                 }
               if ((int)GetTickcount()-tk0>=tk)
                 {  err=2;
                    break;
                 }
               MSComm->InputLen=size>0?(size-count):0;
               vbuf=MSComm->Input;
               int cn=vbuf.ArrayHighBound()+1;
               if (cn>0)
                 {
                   tk0=GetTickcount();
                   for (int i=0;i<cn;i++)
                     {
                        buf【count++】=(BYTE)vbuf.GetElement(i);
                        if (size>0 && count>=size)
                          {   err=3;
                              break;
                          }
                     }
                 }
         }
        size=count;
        return(err);
}

void    PPI::SendBuf(BYTE buf【】,int size)  // 向串口发送size字节
{
        OleVariant vbuf=VarArrayCreate(OPENARRAY(int,(0,(size-1))),varByte);
        for (int i=0;i<size;i++)
           {
              BYTE b=(BYTE)buf【i】;
              vbuf.PutElement(b,i);
           }
        MSComm->Output=vbuf;
}

void    PPI::InitMSComm()           // 初始串口关键参数
{
        // Settings:  9600,e,8,1    // S7-200的缺省通迅参数
        MSComm->InputMode=1;        // 发送格式  0:文本 1:二进
        MSComm->RThreshold=0;       // 让COM1产生接收事件  0/1
        MSComm->InputLen=0;         // 每次接收的字符数
}
//-----------------------------------------------------------------------

在东南亚感受阳光和海滩,还有那浓浓的异国风情,让人心醉

尐お槑孨/叶宏

  • 精华:3帖
  • 求助:0帖
  • 帖子:114帖 | 3593回
  • 年度积分:0
  • 历史总积分:7688
  • 注册:2008年3月16日
发表于:2012-06-30 09:33:57
5楼

一个多星期的试验没有白费,用C++BUILDER6编程,为了调用方式,对子程序进行了对象封装,

      调用方式:
        PPI *ppi=new PPI();
        ppi->MSComm=MSComm1;     // 串口控件
        ppi->timeout=50;                 // 50ms超时
        ppi->InitMSComm();              //  初始串口参数
        MSComm1->PortOpen=true;  // 打开串口

       charbuf【1024】;
        ppi->ReadPPI(_V_,_B_,100,0,20,buf);      // 读 VB100开始20个字节到buf 中
        ppi->ReadNB(_M_,100,10,buf);               //  从MB100开始读10个字节到buf
        ppi->ReadB(_M_,100,buf);                     //  读MB00  一字节         
        bool b=ppi->ReadBit(_Q_,1,0);              //  读Q1.0 一位

        .............................................           //  写PLC


        MSCOmm1->PortOpen=false;                //  关闭串口
        delete  ppi;                                        //  释放对象

                      

  

就 拍 张 照,全 都 肿 了!


 

 

plq

  • 精华:0帖
  • 求助:0帖
  • 帖子:4帖 | 1076回
  • 年度积分:0
  • 历史总积分:1442
  • 注册:2008年3月16日
发表于:2012-07-02 23:39:33
6楼

关注关注关注关注关注!

zhzhang9756

  • 精华:1帖
  • 求助:1帖
  • 帖子:2帖 | 15回
  • 年度积分:0
  • 历史总积分:76
  • 注册:2017年1月22日
发表于:2017-03-02 15:47:23
7楼

大侠,我想知道用VB怎么写I0x(比如I01)?


热门招聘
相关主题

官方公众号

智造工程师