amobbs.com 阿莫电子技术论坛

标题: 开源PLC学习笔记02(再从51开始)——2013_11_8 [打印本页]

作者: oldbeginner    时间: 2013-11-8 11:26
标题: 开源PLC学习笔记02(再从51开始)——2013_11_8
本帖最后由 oldbeginner 于 2013-11-8 12:33 编辑

******************************
在笔记01中,引出了可仿真的精简PLC 51版本,主要是为了研究PLC指令的实现,不能通讯,也只有有限的几个常用命令。这样能更容易把精力集中在理解指令如何实现上,而不会被庞杂的更多的其它功能而影响,而其它功能也会遵循类似方法,一个一个地被研究,最后再综合在一起。
******************************

简短复习一下笔记01,它的核心主体是通过51实现简单的PLC命令,PLC命令是人工输入的,但是符合PLC编程逻辑,并通过仿真实现,不需要开发板很方便。
[attach]150708[/attach]
从图中可看出,二当家(main_PLC)中的代码和PLC中编程逻辑是一致的,实现的功能如下图,
[attach]150709[/attach]

非常生动,我也是这样被吸引才开始写学习笔记的。在笔记01中主要理解了程序流程和LD OUT SET RST指令,在笔记02中将要理解输入端口和输出端口的定义。
*******************************
作者: oldbeginner    时间: 2013-11-8 12:17
看来C语音也需要再回顾加深一下了,端口的定义需要理解下面的结构和联合体。

//定义一个只能按位域寻址的新变量类型
typedef struct {
  unsigned char BIT0: 1;
  unsigned char BIT1: 1;
  unsigned char BIT2: 1;
  unsigned char BIT3: 1;
  unsigned char BIT4: 1;
  unsigned char BIT5: 1;
  unsigned char BIT6: 1;
  unsigned char BIT7: 1;
}TYPE_BIT;  

//定义一个既能按位域寻址也可按字节寻址的新变量类型
typedef union {
  TYPE_BIT       BIT;      //可以按位域寻址

  unsigned char  BYTE;                                        //可以按字节寻址
}TYPE_BIT_BYTE;  

***********************************
结构在51中用的很多,union需要再学习一下,搜一下找到重点:union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置空间,在union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址。http://see.xidian.edu.cn/cpp/html/450.html

看了union的定义之后,基本明白了用法,也可以理解按位域或按字节寻址。
只看输入端口:
1、 16个输入端口,    编号:X0-X7 X10-X17
#define   _X_num      16

2、 16个输入端口,所占内存字节数
#define   _X_BYTE     (_X_num + 7) / 8  

_X_BYTE的计算结果是 (16+7)/8=2,也就是输入端口是双字节,双字节就是16位二进制

3、  位元件 X 存储位
TYPE_BIT_BYTE   data  rX[_X_BYTE];

TYPE_BIT_BYTE和_X_BYTE已经分析了,
使用TYPE_BIT_BYTE来理解对我这样的初学者有些复杂,我还是先理解为结构体,如果在后面的理解中出现问题再更换。

TYPE_BIT   data  rX[2]
可以理解了,TYPE_BIT是个结构体,定义了8个二进制位(类似寄存器),输入端口有2个结构体,正好是16位,对应X0--X7和X10--X17。
作者: liuruoshui    时间: 2013-11-8 12:23
默默的支持楼主!
作者: oldbeginner    时间: 2013-11-8 12:29
oldbeginner 发表于 2013-11-8 12:17
看来C语音也需要再回顾加深一下了,端口的定义需要理解下面的结构和联合体。

//定义一个只能按位域寻址的 ...

[attach]150712[/attach]
[attach]150713[/attach]
我刚开始看下面的的定义时云里雾里的,摸不着门,不过,现在可以解决了。
//-------------------------------------------------------------------------------------//
//  位元件 X存储位                                                     //
//-------------------------------------------------------------------------------------//
#define    _X0_       rX[0].BIT.BIT0   
#define    _X1_       rX[0].BIT.BIT1   
#define    _X2_       rX[0].BIT.BIT2   
#define    _X3_       rX[0].BIT.BIT3   
#define    _X4_       rX[0].BIT.BIT4   
#define    _X5_       rX[0].BIT.BIT5   
#define    _X6_       rX[0].BIT.BIT6   
#define    _X7_       rX[0].BIT.BIT7   
#define    _X10_      rX[1].BIT.BIT0   
#define    _X11_      rX[1].BIT.BIT1   
#define    _X12_      rX[1].BIT.BIT2   
#define    _X13_      rX[1].BIT.BIT3   
#define    _X14_      rX[1].BIT.BIT4   
#define    _X15_      rX[1].BIT.BIT5   
#define    _X16_      rX[1].BIT.BIT6   
#define    _X17_      rX[1].BIT.BIT7  

rx[0]是一个定义了8位二进制的结构体,因为实际上多用了一个联合体,所以中间多出了一个bit(对我来说,理解难度增加了一倍)。还是按照结构体的思想(去掉联合体)。则上面变为
//-------------------------------------------------------------------------------------//
// 把rx作为结构体数组, 位元件 X存储位                                                     //
//-------------------------------------------------------------------------------------//
#define    _X0_       rX[0].BIT0   
#define    _X1_       rX[0].BIT1   
#define    _X2_       rX[0].BIT2   
#define    _X3_       rX[0].BIT3   
。。。。。。
#define    _X7_       rX[0]..BIT7   
#define    _X10_      rX[1].BIT0   
。。。。。。。
#define    _X17_      rX[1].BIT7  

这样看起来清洁多了,也更好理解。

************************************
输出端口采用同样方法,只有8个输出端口

#define    _Y0_       rY[0].BIT.BIT0   
#define    _Y1_       rY[0].BIT.BIT1   
#define    _Y2_       rY[0].BIT.BIT2   
#define    _Y3_       rY[0].BIT.BIT3   
#define    _Y4_       rY[0].BIT.BIT4   
#define    _Y5_       rY[0].BIT.BIT5   
#define    _Y6_       rY[0].BIT.BIT6   
#define    _Y7_       rY[0].BIT.BIT7
  
理解为
#define    _Y0_       rY[0].BIT0   
#define    _Y1_       rY[0].BIT1   
#define    _Y2_       rY[0].BIT2   
#define    _Y3_       rY[0].BIT3   
#define    _Y4_       rY[0].BIT4   
#define    _Y5_       rY[0].BIT5   
#define    _Y6_       rY[0].BIT6   
#define    _Y7_       rY[0].BIT7  


************************************
这样输入端口和输出端口的定义就清楚了。
作者: oldbeginner    时间: 2013-11-8 12:53
本帖最后由 oldbeginner 于 2013-11-8 12:59 编辑
oldbeginner 发表于 2013-11-8 12:29
我刚开始看下面的的定义时云里雾里的,摸不着门,不过,现在可以解决了。
//------------------------- ...


现在就可以理解端口刷新,我刚开始理解为初始化是不正确的。
//------------------------------------------------------------------------------------------------------------
//X输入,Y输出刷新
//------------------------------------------------------------------------------------------------------------
static void RefreshIO(void)
{
        rX[0].BYTE =~P1;
         rX[1].BYTE =~P2;

        P0 = rY[0].BYTE;
}
********************
果然,在这里需要理解为联合体,好在代码短小。

输出最好理解,先看
P0 = rY[0].BYTE;
P0是输出端口,因为联合体内只有一个空间,所以BYTE对应rY[0](在前面的分析中理解为结构体)的8个二进制位。

再看输入端口,
rX[0].BYTE =~P1;
多了一个取反,这时再看电路图,按键的另一端接地,这样当按键按下时,端口是低电平(为0),但是在程序逻辑里要表示为1,所以取反。
同理 rX[1].BYTE =~P2;

这个端口刷新函数为什么定义为静态函数?搜一下,也可以理解。
静态函数会被自动分配在一个一直使用的存储区,直到退出应用程序实例,避免了调用函数时压栈出栈,速度快很多。
关键字“static”,译成中文就是“静态的”,所以内部函数又称静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件。 使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,因为同名也没有关系。
****************************
在PLC_Configure.h中
//  位运算器及 7级中间过渡栈
extern unsigned char   data  ACC_BIT;                        

//  位元件 X,Y 存储位
extern TYPE_BIT_BYTE   data  rX[_X_BYTE] , rY[_Y_BYTE];

搜一下,若本文件 引用别的文件中的全局变量  一定要加上extern 声明一下,http://zhidao.baidu.com/link?url ... 0dUVHC5ChADZstKT8aq


作者: activeleo    时间: 2013-11-8 13:09
资格帖子要严重支持下........
作者: oldbeginner    时间: 2013-11-8 13:10
oldbeginner 发表于 2013-11-8 12:53
现在就可以理解端口刷新,我刚开始理解为初始化是不正确的。
//--------------------------------------- ...

比我想象地内容要少,看起来在理解简单命令上进展还是比较顺利。暂时先不理解其它的命令,开始通讯代码方面的笔记。
[attach]150718[/attach]

仿真和最小代码
[attach]150721[/attach]



作者: hyghyg1234    时间: 2013-11-8 13:52
很通俗易懂,顶
作者: leey    时间: 2013-11-8 14:10
学习了,楼主继续,楼主加油!!
作者: oldbeginner    时间: 2013-11-9 15:32
oldbeginner 发表于 2013-11-8 13:10
比我想象地内容要少,看起来在理解简单命令上进展还是比较顺利。暂时先不理解其它的命令,开始通讯代码方 ...


接下来就是通讯方面的解读,从笔记03开始
http://www.amobbs.com/thread-5558291-1-1.html
作者: LJM4U    时间: 2013-11-10 19:16
快快MARK
作者: YSYJ    时间: 2014-3-5 13:51
楼主学习的非常仔细,紧跟
作者: yx20016    时间: 2015-6-23 10:16
支持楼主,继续学习中
作者: 四平八稳    时间: 2015-8-20 18:10
学习学习,很好的入门资料,
作者: qrsgcslqg2011    时间: 2015-9-21 13:49
支持楼主!
作者: ggggidtf520    时间: 2017-3-29 21:26
楼主 , 我支持你  我在一点一点的学习  ,为你这帖子 我买了 阿莫的帐号~~~~  楼主 加油
作者: sanjianke    时间: 2017-9-14 15:48
这几天都在看楼主的帖子,学到了很多PLC的知识,收获良多。。。理解PLC的实现原理很有帮助,这种思想可以学习。。
作者: tangly2017    时间: 2017-11-17 17:24
受教了,谢谢楼主的分享!!
作者: xuwuhan    时间: 2019-8-26 17:23
花时间好好看。
作者: zbin06    时间: 2020-5-26 10:12
学习了,支持支持




欢迎光临 amobbs.com 阿莫电子技术论坛 (https://www.amobbs.com/) Powered by Discuz! X3.4