开源PLC学习笔记02(再从51开始)——2013_11_8
本帖最后由 oldbeginner 于 2013-11-8 12:33 编辑******************************
在笔记01中,引出了可仿真的精简PLC 51版本,主要是为了研究PLC指令的实现,不能通讯,也只有有限的几个常用命令。这样能更容易把精力集中在理解指令如何实现上,而不会被庞杂的更多的其它功能而影响,而其它功能也会遵循类似方法,一个一个地被研究,最后再综合在一起。
******************************
简短复习一下笔记01,它的核心主体是通过51实现简单的PLC命令,PLC命令是人工输入的,但是符合PLC编程逻辑,并通过仿真实现,不需要开发板很方便。
从图中可看出,二当家(main_PLC)中的代码和PLC中编程逻辑是一致的,实现的功能如下图,
非常生动,我也是这样被吸引才开始写学习笔记的。在笔记01中主要理解了程序流程和LD OUT SET RST指令,在笔记02中将要理解输入端口和输出端口的定义。
******************************* 看来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 charBYTE; //可以按字节寻址
}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 datarX[_X_BYTE];
TYPE_BIT_BYTE和_X_BYTE已经分析了,
使用TYPE_BIT_BYTE来理解对我这样的初学者有些复杂,我还是先理解为结构体,如果在后面的理解中出现问题再更换。
TYPE_BIT datarX
可以理解了,TYPE_BIT是个结构体,定义了8个二进制位(类似寄存器),输入端口有2个结构体,正好是16位,对应X0--X7和X10--X17。 默默的支持楼主! oldbeginner 发表于 2013-11-8 12:17 static/image/common/back.gif
看来C语音也需要再回顾加深一下了,端口的定义需要理解下面的结构和联合体。
//定义一个只能按位域寻址的 ...
我刚开始看下面的的定义时云里雾里的,摸不着门,不过,现在可以解决了。
//-------------------------------------------------------------------------------------//
//位元件 X存储位 //
//-------------------------------------------------------------------------------------//
#define _X0_ rX.BIT.BIT0
#define _X1_ rX.BIT.BIT1
#define _X2_ rX.BIT.BIT2
#define _X3_ rX.BIT.BIT3
#define _X4_ rX.BIT.BIT4
#define _X5_ rX.BIT.BIT5
#define _X6_ rX.BIT.BIT6
#define _X7_ rX.BIT.BIT7
#define _X10_ rX.BIT.BIT0
#define _X11_ rX.BIT.BIT1
#define _X12_ rX.BIT.BIT2
#define _X13_ rX.BIT.BIT3
#define _X14_ rX.BIT.BIT4
#define _X15_ rX.BIT.BIT5
#define _X16_ rX.BIT.BIT6
#define _X17_ rX.BIT.BIT7
rx是一个定义了8位二进制的结构体,因为实际上多用了一个联合体,所以中间多出了一个bit(对我来说,理解难度增加了一倍)。还是按照结构体的思想(去掉联合体)。则上面变为
//-------------------------------------------------------------------------------------//
// 把rx作为结构体数组, 位元件 X存储位 //
//-------------------------------------------------------------------------------------//
#define _X0_ rX.BIT0
#define _X1_ rX.BIT1
#define _X2_ rX.BIT2
#define _X3_ rX.BIT3
。。。。。。
#define _X7_ rX..BIT7
#define _X10_ rX.BIT0
。。。。。。。
#define _X17_ rX.BIT7
这样看起来清洁多了,也更好理解。
************************************
输出端口采用同样方法,只有8个输出端口
把
#define _Y0_ rY.BIT.BIT0
#define _Y1_ rY.BIT.BIT1
#define _Y2_ rY.BIT.BIT2
#define _Y3_ rY.BIT.BIT3
#define _Y4_ rY.BIT.BIT4
#define _Y5_ rY.BIT.BIT5
#define _Y6_ rY.BIT.BIT6
#define _Y7_ rY.BIT.BIT7
理解为
#define _Y0_ rY.BIT0
#define _Y1_ rY.BIT1
#define _Y2_ rY.BIT2
#define _Y3_ rY.BIT3
#define _Y4_ rY.BIT4
#define _Y5_ rY.BIT5
#define _Y6_ rY.BIT6
#define _Y7_ rY.BIT7
************************************
这样输入端口和输出端口的定义就清楚了。 本帖最后由 oldbeginner 于 2013-11-8 12:59 编辑
oldbeginner 发表于 2013-11-8 12:29 static/image/common/back.gif
我刚开始看下面的的定义时云里雾里的,摸不着门,不过,现在可以解决了。
//------------------------- ...
现在就可以理解端口刷新,我刚开始理解为初始化是不正确的。
//------------------------------------------------------------------------------------------------------------
//X输入,Y输出刷新
//------------------------------------------------------------------------------------------------------------
static void RefreshIO(void)
{
rX.BYTE =~P1;
rX.BYTE =~P2;
P0 = rY.BYTE;
}
********************
果然,在这里需要理解为联合体,好在代码短小。
输出最好理解,先看
P0 = rY.BYTE;
P0是输出端口,因为联合体内只有一个空间,所以BYTE对应rY(在前面的分析中理解为结构体)的8个二进制位。
再看输入端口,
rX.BYTE =~P1;
多了一个取反,这时再看电路图,按键的另一端接地,这样当按键按下时,端口是低电平(为0),但是在程序逻辑里要表示为1,所以取反。
同理 rX.BYTE =~P2;
这个端口刷新函数为什么定义为静态函数?搜一下,也可以理解。
静态函数会被自动分配在一个一直使用的存储区,直到退出应用程序实例,避免了调用函数时压栈出栈,速度快很多。
关键字“static”,译成中文就是“静态的”,所以内部函数又称静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件。 使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,因为同名也没有关系。
****************************
在PLC_Configure.h中
//位运算器及 7级中间过渡栈
extern unsigned char dataACC_BIT;
//位元件 X,Y 存储位
extern TYPE_BIT_BYTE datarX , rY;
搜一下,若本文件 引用别的文件中的全局变量一定要加上extern 声明一下,http://zhidao.baidu.com/link?url=j7gCL7jnOsbOvKwovJd-1CdbqURHKsYzUHXi8ooq2Jx-kz9LaIu3qgm7jNxC0cRzT2U0dUVHC5ChADZstKT8aq。
资格帖子要严重支持下........ oldbeginner 发表于 2013-11-8 12:53 static/image/common/back.gif
现在就可以理解端口刷新,我刚开始理解为初始化是不正确的。
//--------------------------------------- ...
比我想象地内容要少,看起来在理解简单命令上进展还是比较顺利。暂时先不理解其它的命令,开始通讯代码方面的笔记。
仿真和最小代码
很通俗易懂,顶 学习了,楼主继续,楼主加油!! oldbeginner 发表于 2013-11-8 13:10 static/image/common/back.gif
比我想象地内容要少,看起来在理解简单命令上进展还是比较顺利。暂时先不理解其它的命令,开始通讯代码方 ...
接下来就是通讯方面的解读,从笔记03开始
http://www.amobbs.com/thread-5558291-1-1.html 快快MARK 楼主学习的非常仔细,紧跟 支持楼主,继续学习中 学习学习,很好的入门资料, 支持楼主! 楼主 , 我支持你我在一点一点的学习,为你这帖子 我买了 阿莫的帐号~~~~楼主 加油 这几天都在看楼主的帖子,学到了很多PLC的知识,收获良多。。。理解PLC的实现原理很有帮助,这种思想可以学习。。 受教了,谢谢楼主的分享!! 花时间好好看。 学习了,支持支持
页:
[1]