工控之家

 找回密码
加入工控之家

科威PLC芯片组开发实例(二)

[复制链接]
发表于 2012-7-5 08:40:02 | 显示全部楼层 |阅读模式
工欲善其事,必先磨其器。

做科威PLC芯片组开发,需要准备什么工具呢?

不必着急,给你一一道来:
1.    KEIL2或者KEIL3,这个是必须的。下载地址笔者就不贴了,网上都有自己找。此款工具是你编写驱动所必须的。当然你也可以用新华龙公司提供的编程工具Cynal来做,殊途同归。
2.    DOWNHEX,此软件属科威公司开发,专用于驱动下载。所以你不要用KEIL自带的下载功能进行驱动下载,没有用,非用此工具下载不可。要搞清楚的是,现在你需要编写的只是驱动,科威PLC芯片组的实时操作系统会将你的驱动嵌入到系统内,驱动并不是要覆盖这个系统,而只是补充此系统。驱动中你所编写的功能会被操作系统调用并执行。DOWNHEX的作用,就是将你编写的驱动形成的HEX代码保存在芯片组中的一个固定区域,系统运行过程中会调用你写的程序。
3.    CANSET,此软件也属科威公司开发,专用于编写CAN网络设置参数,也就是说,你想要激活科威PLC芯片组的CAN网络通讯功能,就必须使用这款工具。如果你不用到此功能,那你当然也可以不必使用此工具,但是做科威PLC芯片组开发不用到CAN功能,那可是暴殄天物,因为此功能可是科威PLC芯片组最大的亮点特色之一哟!
4.    FX2N编程软件,严格说起来,这个和编写驱动没有太大关系,但是,此软件和科威PLC芯片组可是大大的有关系!这个软件是编写梯形图的软件,想要让你的PLC运行梯形图,当然还得靠它。

以上的前3种工具,笔者会在开发过程中告诉你应该怎样使用,所以你只要先有个大概的概念即可。

除此之外,你还得有一本C8051F040的说明书,有许多寄存器的功能定义在使用过程中你非得查阅此书不可。网上有中文的和英文的版本,笔者用的是中文的,呵呵,如果喜好用英文的,那你是高手!什么?你已经把说明书的内容都烂熟于心了?那你是高手中的高手,这段话当我没说…ORZ

在网上找到c8051F040.inc的头文件,此头文件包含了所有F040的寄存器地址定义,开发过程中需要把此文件加到你的工程之中。如果不加,那么你所用的所有F040的寄存器,编译器都会提示你undefined。

还得找到easycore.inc以及easycore.lib两个文件。具体这两个文件的作用,我们以后再谈。

在从事开发之前,如果你对F040完全不了解,建议你还是花个几天时间阅读一下它的说明书。当然,想要把它完全都看懂,没有一定编程实际经验的话,绝对是个不可能完成的任务。只需要在看了以后,能够对此CPU的性能和各功能模块有一定了解即可。说白了,笔者认为,此说明书存在的目的,就是为了能在开发过程中遇到的问题有个权威的查阅之处,而并不是去把它死记硬背,那是完全没有必要的事情。

下一讲,我们会正式进入正题,讲解如何编写一个简单的驱动。

PS:在本文提到的各种工具和资料,如果各位懒得去搜索,直接把邮箱贴在下面,笔者看到了会给你发过去^-^。

本帖首发中国工控网科威PLC论坛,转载请声明!
发表于 2012-7-5 11:16:23 | 显示全部楼层
如何搭建用户驱动环境?

首先,教大家如何使用KEIL3创建一个用户驱动工程(笔者目前用的是KEIL3,只能就此讲解,所以你用的如果是KEIL2或者Cynal,那么就自行摸索,总的来说,功能上都相差不大。)

首先要注册KEIL3,使之可以编译超过2K范围的代码。至于怎么注册,请在网上找,笔者不在此赘述。

新建一个文件夹,此文件夹为你将要做的项目文件夹(比如D:\\PLC_DRIVE,以下的教程皆假定你的项目在此文件夹内来阐述)。
然后打开KEIL3,在菜单栏选择Project→New Project…,将会弹出一个名为“Create New Project”的对话框,在对话框中选择D:\\PLC_DRIVE并双击进入,创建一个名为“PLCDR”的uv2文件。

接下来会弹出一个选择芯片类型的对话框,下拉竖直条选择“Silicon Laboratories, Inc.”展开选择“C8051F040”,点击确定。

随后系统问你是否需要“Copy Standard 8051 Startup Code to Project Folder and Add File to Project?”,这句话的意思是问你是否需要为你的项目添加标准的8051规范。这个东西对我们这个项目的开发没多大用,推荐你选择否,反正笔者就是这么干的。
这个时候基本的项目框架就搭建起来了,现在是时候为你的驱动项目添加“血肉”了。

选择菜单中的File→New…,点击“保存”,将此Text1空白文档保存在D:\\PLC_DRIVE中,并更改此文件名为“PLCDR.ASM”,注意后缀名是“.ASM”而不是“.TXT”了。

这个时候,细心的你可能已经发现了,我们将会用51汇编来实现驱动程序的编写。在这个汇编已经没落,甚至连C也慢慢的被人抛弃的时代, C#,.NET,.COM,JAVA,J2EE等流行语言及技术大行其道的今天,我们为什么还要用汇编来编写程序呢?而且是在KEIL也是支持C语言的情况下我们做出的选择,看似更加的没有道理。其实这是仁者见仁,智者见智的。在笔者看来,汇编虽然比C更加的晦涩难懂,但它最贴近硬件的特性却能够使我们的驱动程序更加的高效,在F040这个8位小型CPU上,使用汇编语言能更加让我们“精打细算”,使我们的每条语句都精确到0.0X个US(科威PLC芯片组的系统时钟频率为24.5MHZ,也是F040所能达到的最高系统时钟频率),PLC是做什么的?当然是做控制的,所以实时性,高效性以及安全性是PLC永恒的话题。我们选择汇编语言作为驱动程序的开发的理由也正因如此。当然,如果你对汇编一窍不通的话,笔者也建议你耐心把下面的教程看完,虽然汇编与C的差异性还是蛮大的,但是多多少少会对你对芯片组开发有一定的帮助。

呵呵,话题扯远了,言归正转,你注意到左边那个“Project Workspace”浮动工具栏没?双击里面的Source Group 1,路径选择到“D:\\PLC_DRIVE”,选择“PLCDR.ASM”并点击确定。什么?没有这个“PLCDR.ASM”?那你得把文件类型改为“all files”才能看的到。个人BS了KEIL公司一下,居然连.ASM的文件类型都没有…看来也是个喜新厌旧的主~
这个时候,你会发现Source Group 1左边有个小+号,点击下拉,PLCDR.ASM跃然纸上了,哦不,是跃然于显示屏上了。

至此,准备工作已经完成,下一讲我们就要介绍此项目工程在KEIL中的一些参数设置,以及科威PLC芯片组用户驱动开发所需要准备的几个头文件和函数库。

本帖首发中国工控网科威PLC论坛,转载请声明!
发表于 2012-7-5 13:52:43 | 显示全部楼层
到底我该怎么编写一个用户驱动呢?

上一讲我们配置了用户驱动在KEIL3中的工程环境,下面我们来谈谈PLCDR项目在KEIL中应该设置哪些参数。

首先,你得找到一个名为“Options For Target”的图标,就是那个“LAOD”图标旁边那个象个魔法棒的图案,点击弹出“Options For Target Target1”对话框。当然你也可以选择菜单的Project→Options For Target Target1来把此对话框调出。

找到OutPut选项,勾上下面的“Create HEX File ”的单选框,前面我们曾经说过,驱动加载到科威PLC芯片组中是要以HEX形式的文件通过DOWNHEX软件下载来实现的。所以得让KEIL给你生成一个HEX才行。

然后找到A51选项,将“Define 8051 SFR Names”前面的勾去掉。如果启用这个功能,KEIL就会在编译你的项目的时候,自动调用51默认的寄存器定义,那么就会和前面我们所提到的c8051F040.inc这个头文件所定义的寄存器相冲突。结果会在你编译项目的过程中,会出现一大堆的“redefined”错误。

除此之外,都默认就好,点击确认完成参数配置。

接下来,将你找到的c8051F040.inc,easycore.inc以及easycore.lib这3个文件都复制到D:\\PLC_DRIVE路径下,并在此路径下新建一个“USER_DATA.inc”的文件。

下面我们说说,这几个文件的含义:
1.    c8051F040.inc,这个笔者前面讲过,不再重复;
2.    easycore.inc,你可以打开它来看看,会发现这里面定义了用户所可以用到的寄存器组还有相关的变量地址。F040.中.共.定义了4个R0~R7寄存器组,用户只能使用0区,其他的对不起,内核(我们习惯把芯片组内的实时操作系统称之为内核,很形象,不是吗?)都给占用了~然后是BRAM_USER,这个是用户可用的位变量寻址,采用的是直接位寻址方式,一共可以定义32个位,也就是4个字节。少了点,可是没办法,内核占了大头…DRAM_USER,这个是用户可用的字节变量寻址,采用的是直接寻址方式,可以定义16个,还是少了点,但是还是没办法…-_-!最后是XRAM_USER,这个用户能用的倒是多啊,有几千个,但是可惜的是它是间接字节寻址。系统读取这个区域的数据,那效率是刷刷往下降啊!但是还是得用,要不然变量不够啊,呵呵。F040要是直接寻址的存储空间再大些就好了,可是这是笔者的一相情愿,残念……最后面就是有关梯形图的变量地址空间了,你可以看到D,M,S等梯形图内所用的这些寄存器在内核里面所占的地址。中间的那一块暂时跳过不讲,以后找机会给大家说明,不过可能有的读者已经了解那些定义大概是什么意思了,不管了解不了解,让我们继续GO ON!
3.    easycore.lib,这个库直接从KEIL里面是看不了的,你想要看它,就从记事本里面看吧。里面是为了方便用户所定义的一些系统函数,比如双字节乘除,浮点数运算等等,如果你要调用这些函数,注意出口入口要设置对哦。
4.    USER_DATA.inc,这个文件暂时是空白的,留给你自己发挥创造的,你可以在里面定义自己的位变量啦,字节变量啦,还有变量重定义等。比如你在里面写一句“MODE_DATA      EQU  DRAM_USER  ;模式选择”,意思就是你将直接字节寻址的第一个单元赋予了MODE_ONOFF这个名字,那么你在驱动中就可以直接调用MODE_DATA这个变量啦。
后面那个分号以及分号以后的文字,是这条语句的注释。在KEIL给51汇编加注释有2中方法,一个是“;”,相当于C里面的“//”,另外一个和C相同,是“/* */”。


下一讲,笔者将讲述科威PLC芯片组开发用户驱动的具体格式。

本帖首发中国工控网科威PLC论坛,转载请声明!
发表于 2012-7-5 16:29:03 | 显示全部楼层
樓主能否一次性發完,感覺都有點像大型電視劇一樣!
发表于 2012-7-5 19:05:23 | 显示全部楼层
这一讲里面将会讲解科威PLC芯片组开发用户驱动的具体格式。笔者始终认为,学编程,从看代码开始是捷径!所以,我们在PCLDR.ASM内添加以下一段代码。

$INCLUDE(C8051F040.INC)    ; Register definition file.    -------------------1   
$INCLUDE(easycore.INC)        ; easycore 符号定义------------------------2            
$INCLUDE(EASYCORE.LIB)    ; easycore 子程序---------------------------3            
$INCLUDE(user_data.INC)        ; 用户程序变量定义------------------------4            
;================中断向量重定向地址=======================
                ORG        0E000H                    
                ORG        0E003H            ;external interrupt0 vecter (INT0)------5
                ORG        0E013H            ;external interrupt1(INT1)---------------6
                ORG        0E033H            ;Serial Peripheral Interface(SPI)--------7
                ORG        0E03BH            ;SMBus interface-------------------------8
                ORG        0E043H            ;ADC0 Window Comparator;----------9
                ORG        0E04BH            ;Programmable Counter Array--------10
                ORG        0E053H            ;Comparator 0---------------------------11
                ORG        0E05BH            ;Comparator 1---------------------------12
                ORG        0E063H            ;Comparator 2    --------------------------13
                ORG        0E07BH            ;ADC0 end of Conversion-------------14
                ORG        0E083H            ;Timer    4-------------------------------15
                ORG        0E08BH            ;ADC2 end of Conversion-------------16
                ORG        0E093H            ;ADC2 Window Comparator-----------17
;===============用户应用程序调用入口====================
                ORG        0E0A0H            ;用户端口初始化
                LJMP        INIT_CONFIG     ;----------------------- --------------------18   
                ORG        0E0A3H            ;用户上电初始化
                LJMP        INIT_START        ;----------------------- --------------------19   
                ORG        0E0A6H            ;用户设置初始化
                LJMP        INIT_SET        ;----------------------- --------------------20   
                ORG        0E0A9H            ;用户运行初始化
                LJMP        INIT_RUN        ;----------------------- --------------------21
                ORG        0E0ACH            ;演算周期扫描
                LJMP        SCAN            ;----------------------- --------------------22
                ORG        0E0B0H            ;指令周期扫描
                LJMP        STEP            ;----------------------- --------------------23
                ORG        0E0B3H            ;2.5MS周期扫描            
                LJMP        TMS            ;----------------------- --------------------24
                        
                ORG         0E100H            ;----------------------- --------------------25


INIT_CONFIG:
                RET

INIT_START:
                RET

INIT_SET:
                RET

INIT_RUN:
                RET

STEP:
                RET

TMS:
                RET

SCAN:
                RET

END        ;-------------------------------------------------------------26

然后点击编译,如无意外,KEIL将会编译成功并生成“PLCDR.HEX”文件,该文件可以在项目路径下找到。

至此,你的第一个驱动程序已经编写完成。只不过这是一个简单的驱动程序,简单到什么也没有的驱动程序。嘿嘿,如果把这段HEX代码下到你的PLC内,PLC的IO口可能会乱跳的哦~不过,梯形图的解释倒是独立于驱动之外的,加载了一个什么也没有的驱动,PLC芯片组也是可以正常运行梯形图的。

在下一讲里,笔者将会逐句给你分析以上程序的每一条语句哦~其实从那些简短的注释里,相信不少读者已经看出了些许端倪了。

本帖首发中国工控网科威PLC论坛,转载请声明!
发表于 2012-7-5 21:41:43 | 显示全部楼层
上讲驱动语句解释:

在上面一讲,笔者给出了一段基本用户驱动语句段的代码,下面是详细解释它们的时候了。

1.    第1~4句:是将3个头文件和1个库文件添加到你的驱动工程项目中,这个就不在解释了。

2.    第5~24句:是将F040的中断跳转重定义,查阅F040的说明书我们可以看到,0X0003H是外部中断0的代码起始地址,在内核中,将外部中断0的起始代码重新定义到0E003H开始了。这里就产生了3个问题:
①    为什么要将中断的起始代码地址重定义?
答:这个是为了方便代码管理,前面笔者曾经提到过,驱动下载到内核里,是存放在一
块相应的地址空间由内核调用的。这个地址你现在可以看到,是从0XE000H开始的,由于用户中断也属用户驱动的一部分,所以,它的这部分代码也必须保存到0XE000H以后的一个地址段内,而默认的中断起始代码从哪里开始呢?以外部中断0为例,你可以从说明书上看到,它的起始地址是0X0003H,这样用户驱动流程代码和用户驱动中断代码就被分成了2个地址段,给内核的管理造成了麻烦。所以我们必须要进行中断代码地址重定义的工作。
②    如何实现中断的起始代码地址重定义?
答:还是以外部中断0为例,内核在这里直接用了一个“LJMP    0XE003H”即完成了地址重定义的工作,是不是很简单?
③    科威PLC芯片组还有其他的中断重定义了吗?我可以用它们吗?
答:我们只能够用到上面代码给出的这些中断,还有的中断比如T0,T1等中断已被内核占用,我们编写用户驱动就无缘使用它们啦!

3.    第18句:用户I/O口配置程序:根据设计的输入输出功能配置相应的端口(推挽或者漏级),用户不可配置的I/O口资源为P4.4、P4.5、P4.6、P4.7、P5、P6、P7及UART0。理由还是那句话:内核已占用…此段程序会在内核重新上电后调用一次。

4.    第19句:用户上电初始化程序:用户嵌入程序中用到的输入输出变量,中间变量,指针变量,位变量等在重新上电后必需进行初始化处理,此段程序在内核重新上电后调用一次。

5.    第20句:用户设置初始化程序:内核重新上电后进入梯型图下载状态或内核从梯型图运型状态进入梯型图下载状态时调用此程序一次。

6.    第21句:用户运行初始化程序:内核重新上电后第一次运行梯型图或内核从下载梯型图状态进入梯型图运行状态时调用此程序一次。这个子程序大家可以看到,与上面一个的流程是相反的。

7.    第22句:用户演算周期扫描程序:所有梯形图执行完后,即调用该程序,调用周期为梯型图演算周期,一般的数据处理、开关量输入/输出的刷新及代码执行时间较长的程序均放在此程序中执行。

8.    第23句:用户每步执行程序:梯形图每执行一步,即调用此程序一次。需要快速执行的事件可在此程序或用户中断程序中完成,内核周期性地调用此程序,周期小于50US。
50US有多少个指令周期呢?我们可以算算:设1个指令周期的执行时间为t,系统时钟频率为f,那么1S=1000000US, f = 24.5MHZ,那么t = 1000000/24500000 = 0.04US,也就是说50US可以执行的指令周期数为50/0.04 = 1250个。这里有两点需要说明一下,一条语句所占的指令周期并不一定只有一个,比如NOP指令所占的指令周期为1,但是CJNE指令就不止1个了,具体占了几个笔者不记得了~,这个可以在说明书里面查到。另外一点是假设你编写的总代码折合成指令周期数是2000个,那是不是就不能满足要求了呢?答案是不一定,只要你最长的一次执行过程所花费的指令周期数不超过1250个就行了,因为往往在程序里会有条件跳转的代码。举个例子吧,假设你的STEP里面有2个条件执行过程A和B,A条件的执行过程一共有1100个指令周期,B条件有900个。虽然A+B一共有2000个超过了1250个,但是因为是条件跳转,程序是不可能同时执行A和B的。所以算起来你的程序最长的指令周期数是1100个而不是2000个!哎呀,估计越讲越难让人理解了…打住,往下走吧,毕竟,计算每条语句所占用的系统时间并将其代码优化都是些达人们,我们还是先看简单的。

9.    第24句:用户2.5mS定时运行程序:需要定时采样的流程可放在此程序中完成,但该段程序代码执行时间必须小于50 US。数据处理程序不宜放在此段程序中执行。注意这里是内核给提供的软中断,如果你的驱动里面没有什么高级的中断并频繁发生,那么它就是2.5ms调用一次,很准!同时你得注意,它的返回语句不是“RETI”而是“RET”,为什么?因为它是“软”的嘛,是内核给定义的,又不是F040的规范中断,呵呵!

10.    第25句:用户驱动程序编程起始位置,从这里往下就是你自由发挥的空间了哦~

11.    第26句:别忘了给你的驱动程序加个完美的“句号”。

看到这里,你应该对科威PLC芯片组的开发有了一定的了解了吧。?完全没了解??看来笔者的水平差了点,就请将就多看几遍吧…-_-!不是有一句话就作“书读百遍,其意自现”的么。有问题或不懂的给回下贴嘛,笔者看到了一定给你解答^-^~!

在下一讲里面,就要开始实战了,笔者将基于科威公司出产的EASY-M0806R这款PLC重新编写IO驱动程序,手头上有这款PLC的朋友也可以跟着做哦~!

本帖首发中国工控网科威PLC论坛,转载请声明!
发表于 2012-7-6 00:18:03 | 显示全部楼层
实战开始,苦手对象:EASY-M0806R

首先,我们得搞清楚,EASY-M0806R的IO引脚的分配情况,这款PLC有8个输入点,6个输出点,那么就相应的有8+6 = 14个IO引脚对应它们的输入和输出,对应原理图我们得知:
8个输入点对应的引脚是:
I0→P3.7     I1→P3.6  I2→P3.5  I3→P3.4  I4→P3.3  I5→P3.2  I6→P3.1  I7→P3.0

6个输出点对应的引脚是:
OUT0→P1.0  OUT1→P1.1  OUT2→P1.2  OUT3→P1.3  OUT4→P1.4  OUT5→P1.5

其次,每个输入输出点都对应一个LED,当输入输出点吸合的时候,对应的LED将被点亮,那么对应原理图我们得知14个LED对应的引脚是:
ILED0→P2.0  ILED1→P2.1  ILED2→P2.2  ILED3→P2.3  ILED4→P2.4  ILED5→P2.5
ILED6→P2.6  ILED7→P2.7
OLED0→P0.4  OLED1→P0.5  OLED2→P0.6  OLED3→P0.7  OLED4→P4.1  OLED5→P4.0

与此同时,PLC还有一个RUN/SET的输入,该输入负责管理PLC的运行状态和下载状态,对应着不同的状态,有一个专门LED点亮/熄灭来判断此输入的状态,一般来说,运行状态时,该LED被点亮,下载状态则反之。根据原理图我们得知:
RUN/SET-LED→P4.3

PLC如果错误的被执行,应该还有一个错误的LED将被点亮,这个LED对应的引脚为:
ERR-LED→P4.2
那么我们怎么得知PLC运行/下载的状态,还有出错的状态呢?请看easycore.inc文件,有3个变量定义:
KEY_SET            EQU        3FH        ;1有效(下载梯形图)
KEY_PRO            EQU        3EH        ;0有效(下载用户程序)
PLC_PRO_ERR        EQU        3DH        ;梯形图错误标志,1有效
这个是我们前几节所没有讲到的,通过检测这些位变量,我们就可以对RUN/SET-LED和ERR-LED进行控制了。

知道了这些以后,我们就对EASY-M0806R的IO引脚分配有了大致的了解,趁此机会,我们把easycore.inc最后剩下没讲完的变量也拉出来遛一下吧~
M0~M15:这16个字节变量可是直接寻址方式的哟,但是应用它们有个局限性,那就是必须得在SCAN里面应用,其他地方是不允许调用这16个字节变量的,如果你非要在其他地方使用,那么就必须得把它们压栈,不过还是不推荐此方法,真的要压栈的话,还不如压公共直接寻址变量区DRAM_USER区域呢。

FLOAT_M1~ FLOAT_M4,W_R0~ W_R7,W_DATA:这几个变量是专门调用easycore.lib函数库里面的函数所要用到的出口入口的变量。大致了解一下它们的含义便行,如果你到了需要调用easycore.lib函数库里面的函数这个阶段,那么本文对你来说,相信应该已经没有多大意义了^-^~!

下一讲我们将分模块来详细叙述如何根据我们所掌握的IO口引脚信息,来填充我们的驱动项目工程。

PS:本节所讲的IO口配置可能会与实际IO口配置略有出入,大家当以实际的原理图为准!

本帖首发中国工控网科威PLC论坛,转载请声明!
发表于 2012-7-6 02:54:23 | 显示全部楼层
实战攻坚!

上一讲我们了解了EASY-M0806R的IO口分配情况以及各种LED的引脚情况,那么下面我们就要开始一步一步的编写我们的驱动代码了~

首先是INIT_CONFIG用户驱动子程序,该程序里面,要添加的内容在前文中已有说明。那我们该如何配置这些IO口方式呢?

INIT_CONFIG
首先我们的第一句话便是:
MOV    SFRPAGE,#0FH
那么SFRPAGE是什么意思呢?呵呵,这就要看你对以前看的F040说明书熟悉程度了,什么?你完全不知道??-_-!那就现翻吧~笔者当年也好不到哪去,嘿嘿。
从说明书中可得知,这是一个选择SFR页数的功能寄存器,我们要调配IO端口的参数寄存器PnMDOUT,就首先得把SFR页数置为15,这个是F040规划的,就不再剥根问底了。值得提出的是,初学者常犯的一个错误就是在配置功能寄存器的时候,没有及时更改它所属的SFR页数,导致程序运行错误。比如,配置了P0MDOUT功能寄存器,这个时候你是把SFRPAGE置成15了。但是在调配TMR4CN功能寄存器的时候,却忘了把SFRPAGE改为2。这个时候错误便不可避免的出现了。
其次,我们开始配置上面所涉及到的EASY-M0806R的IO口的配置寄存器了,也许有的朋友会问到了,怎么初始化没有延迟啊,选择系统时钟频率啊,调配交叉开关啊?这些步骤确实是一个操作系统运行初始化所必须要配置的部分,但是在我们的驱动里面就不用重新配置了,因为内核里面已经定义过了一次。当然,也许你做的PLC有特殊的用途需要重新配置这些,那么也可以,不过还是那句话,时刻记住以内核为主,所以在重新配置这些之前你要考虑清楚怎么配置才不会和内核的配置起冲突。
科威PLC一般来说,输入端口要配置成漏极方式,输入端口要配置成推挽方式,LED也都是推挽方式。当然具体的要视其原理图决定。根据这个原则,我们配置了下面4条语句:
ORL    P0MDOUT,#0F0H        ;1
ORL    P1MDOUT,#3FH        ;2
ORL    P2MDOUT,#0FFH        ;3
ANL    P3MDOUT,#00H        ;4
ORL    P4MDOUT,#03H        ;5
也许细心的你会问:为什么都要用ORL和ANL指令而不是用MOV呢?这个就是笔者的习惯了,ORL和ANL指令的好处是只用改变你所需要的位,而其他的可以保持不变,以免引起不必要的错误。
我们来分析这4句话的含义:
1.    这句是配置P0端口的输出方式的,由上一讲我们得知,整个驱动用到P0口的有:
OLED0→P0.4  OLED1→P0.5  OLED2→P0.6  OLED3→P0.7,由于LED需要配置成推挽输出方式,那么我们就将P0MDOUT的高4位都配置成1即可。
2.    这句是配置P1端口的输出方式的,整个驱动用到P1口的有:
OUT0→P1.0  OUT1→P1.1  OUT2→P1.2  OUT3→P1.3  OUT4→P1.4  OUT5→P1.5,由于输出端口需要配置成推挽输出方式,那么我们把P1MDOUT的低6位都配置成1即可。
3.    这句是配置P2端口的输出方式的,整个驱动用到P2口的有:
ILED0→P2.0  ILED1→P2.1  ILED2→P2.2  ILED3→P2.3  ILED4→P2.4  ILED5→P2.5  ILED6→P2.6  ILED7→P2.7,由于LED需要配置成推挽输出方式,那么我们就将P2MDOUT的所有8位都配置成1即可。
4.    这句是配置P3端口的输出方式的,整个驱动用到P3口的有:
I0→P3.7     I1→P3.6  I2→P3.5  I3→P3.4  I4→P3.3  I5→P3.2  I6→P3.1  I7→P3.0,由于输入端口需要配置成漏极输出方式,故我们把整个P3口输出都配置成0。
5.    这句是配置P4端口的输出方式的,整个驱动用到P4口的有:
OLED4→P4.1  OLED5→P4.0,同理,我们把P4MDOUT的低2位配置成1。

这样,整个INIT_CONFIG便配置完成了。下一讲笔者将讲述其他用户驱动子程序在EASY-M0806R上的实现。

本帖首发中国工控网科威PLC论坛,转载请声明!
发表于 2012-7-6 08:07:03 | 显示全部楼层
实战攻坚!

下面我们讲讲该在TMS用户驱动子程序里面写些什么代码。

首先笔者得说说科威PLC的输入端口采样原理,为什么要进行输入端口采样呢?答案很简单,就是为了滤波。在PLC实际运行过程中,X端口可能会因为现场干扰收到一些毛刺信号,这些毛刺信号如果不进行处理,就会影响到PLC对X端口的状态的判断,那么我们必须得剔除掉这些毛刺,使系统工作在一个稳定的环境。
我们规定,如果连续采样8次X端口的值都是一致的,就判断此刻X端口的状态是实际的输入状态,这个也就是为什么我们把INPUT_CNT这个变量设置为8的原因。

还是老规矩,笔者贴出TMS的代码并为大家分析:
TMS
TMS:            MOV    C,KEY_SET            ;1
                MOV    P4.3,C                ;2
                MOV    C,PLC_PRO_ERR        ;3
                CPL        C                    ;4
                MOV    P4.2,C                ;5
                MOV    A,INPUT_CNT        ;6
                JNZ        TMS1                ;7
                RET        

TMS1:            DEC    A                    ;8
                MOV    DPTR,#XINPUT        ;9
                ADD    A,DPL                ;10
                MOV    DPL,A                ;11
                MOV    A,DPH                ;12
                ADDC    A,#00H                ;13
                MOV    DPH,A                ;14   
                MOV    A,P3                ;15
                MOVX    @DPTR,A            ;16
                DEC    INPUT_CNT            ;17
                RET

1.    第1~5句:这4条语句是给RUN/SET和ERR两个灯赋状态的。在原理图中看到,由于ERR的LED与实际的P4.2中间反了一次向,故此在程序中也需要对此端口反向赋值。
2.    第6句:取INPUT_CNT当前值赋给寄存器A
3.    第7句:这句是一句跳转指令,作用是看对X输入端口当前的8次采样完成了没有,如果完成了,就直接返回,在SCAN用户驱动子程序会对其X0~X7寄存器的值进行更新;如果8次采样没有完成,则跳转到TMS1中进行X输入端口采样。
4.    第8~16句:将P3端口的值(即当前X输入端口的采样值)存放到从#XINPUT+7开始到#XINPUT一共8个单元。值得注意的是,完成8次采样的时间为2.5ms * 8 = 20ms。也就是说,从第1次采样开始到8次采样结束需要20ms的时间。结束时,#XINPUT~#XINPUT+7这8个单元的地址已被填充,等待SCAN用户驱动子程序的处理。这段程序通过改变采样指针DPTR的DPH和DPL,使其指向不同的外部寻址单元,这个小技巧希望大家能够熟练掌握。
5.    第17句:将INPUT_CNT减1。不要忘记这句话,否则你的程序将始终填充#XINPUT+7这个单元的数据,采样指针永远也指不到#XINPUT+6和其以下的单元。

好了,TMS就给大家分析完了,下一讲笔者将给大家讲述最后一个部分:SCAN。

本帖首发中国工控网科威PLC论坛,转载请声明!
发表于 2012-7-6 10:43:24 | 显示全部楼层
实战攻坚!

本节,给大家讲解针对EASY-M0806R这款PLC的SCAN用户驱动子程序该完成的功能。

通过前面的讲解,大家应该知道,SCAN是在梯形图完成一次扫描以后被系统调用的程序,在这个程序里面,我们需要更新输入输出口的状态以及LED的状态。

SCAN
SCAN:            LCALL    USER_SCAN_O            ;输出端口和LED更新
                LCALL    USER_SCAN_I            ;输入端口和LED更新
                RET

USER_SCAN_O:  
;刷新输出端口
MOV    DPTR,#RAM_PY+1        ;Y00--Y05
                MOVX    A,@DPTR
                CPL        A
                MOV    SFRPAGE,#0FH
                ANL    A,#3FH                    
                MOV    B,A
                MOV    A,P1
                ANL    A,#0C0H                    
                ORL    A,B                        ;使P1.6,P1.7保持原来的状态
                MOV    P1,A                    ;刷新输出
;刷新输出LED
                 SWAP    A
                MOV    C,ACC.4            
                MOV    P0.4,C
                MOV    C,ACC.5
                MOV    P0.5,C
                MOV    C,ACC.6
                MOV    P0.6,C
                MOV    C,ACC.7
                MOV    P0.7,C
                MOV    C,ACC.0
                MOV    P4.1,C
                MOV    C,ACC.1
                MOV    P4.0,C
                RET

                        
USER_SCAN_I:  MOV    A,INPUT_CNT
                JZ        USER_SCAN_I1
                RET
                                                               
USER_SCAN_I1:    LCALL    USER_SCAN_IS    ;判断8次采样值是否相同   
                JB        F0,USER_SCAN_I2
                MOV    C,ACC.7            ;调整输入口
                MOV    F0,C
                MOV    C,ACC.0
                MOV    ACC.7,C
                MOV    C,F0
                MOV    ACC.0,C
                MOV    C,ACC.6
                MOV    F0,C
                MOV    C,ACC.1
                MOV    ACC.6,C
                MOV    C,F0
                MOV    ACC.1,C
                MOV    C,ACC.5
                MOV    F0,C
                MOV    C,ACC.2
                MOV    ACC.5,C
                MOV    C,F0
                MOV    ACC.2,C
                MOV    C,ACC.4
                MOV    F0,C
                MOV    C,ACC.3
                MOV    ACC.4,C
                MOV    C,F0
                MOV    ACC.3,C
                MOV    INPUT_PORTA,A        ;相同则更新输入数据寄存器
                MOV    DPTR,#RAM_PX+1    ;X00--X07
                MOV    A,INPUT_PORTA
                MOVX    @DPTR,A            ;更新X00--X07
;刷新输入LED
MOV    A, INPUT_PORTA
CPL        A
                MOV    P2,A
USER_SCAN_I2:    MOV    INPUT_CNT,#08H
                RET

;判断8个采样数据是否相同,相同则F0=0
USER_SCAN_IS:    MOV    DPTR,#XINPUT
                MOVX    A,@DPTR
                MOV    M0,A
                MOV    R7,#7

USER_SCAN_IS1:    INC        DPTR
                MOVX    A,@DPTR
                CJNE    A,M0,USER_SCAN_IS2
                DJNZ    R7,USER_SCAN_IS1
                CLR        F0
                RET

USER_SCAN_IS2:    SETB    F0
                RET   

关于本段代码的详细说明,笔者将改变一下方式,在下面的回帖为大家讲解。当然笔者在关键处已经做了注释,大家可以先看看并结合之前的程序研究一下,发帖提出问题,看看笔者的回答与自己的理解有何偏差。

如果没有人发帖,笔者自然是希望看文章的朋友们都理解了笔者的代码,就小小的懒惰一回吧,嘿嘿~!

当然如果大家的问题很多,那么笔者就写“科威PLC芯片组开发实例(十二)”,详细给大家说明SCAN中代码的含义。

本帖首发中国工控网科威PLC论坛,转载请声明!
您需要登录后才可以回帖 登录 | 加入工控之家

本版积分规则

QQ|手机版|小黑屋|Archiver|工控之家 ( 鲁ICP备12015736号-1 )

GMT+8, 2024-10-6 08:13 , Processed in 0.686530 second(s), 49 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表