找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 11343|回复: 0
打印 上一主题 下一主题
收起左侧

用单片机制作PLC(多路故障报警系统)附源码+梯形图+仿真+论文

[复制链接]
跳转到指定楼层
楼主
简易可编程控制器PLC的单片机实现的全部设计资料包:


电路原理图如下:




2.3 用单片机实现PLC的总体设计
本次设计用AT89C52单片机设计了一个4输入4输出的简单PLC。
该PLC含有10个定时器和10个计数器,每个定时器的最长定时时间为3276.75秒,每个计数器的最大计数值为65535。
该PLC的输入方式为直流开关量,输入电压为24V。
输出采用继电器输出方式,采用汇科继电器HK4100F-24V-SHG,该继电器是小型、小功率继电器,触点形式是常开型,额定电压为DC24V,直流电阻为1Ω,吸合电流为2A,释放电流也为2A,线圈功率为4W,额定工作频率为5Hz。
为了提高系统的抗干扰能力,输入输出电路中都使用了光电耦合器。光电耦合器采用TLP521-1。
该PLC具有与计算通讯能力,可以在计算机上下载程序。
设计的PLC总体外观图如图2.15所示。

图2.15 PLC总体设计的外观图

图2.15中,输入端口X0、X1、X2和X3分别于单片机的P0.0、P0.1、P0.2和P0.3通过输入电路相连接。输出端口口Y0、Y1、Y2和Y3分别于单片机的P1.0、P1.1、P1.2和P1.3通过输出电路相连接。+24V是输入电源,电源与输入端口间可以接开关等开关量输入装置。输出端口和yCOM端之间接用户的控制电路,可以是简单的LED灯,也可以是直流电机、交流电机。用户控制电路中的电源可以是直流也可以是交流。
根据输入端口的状态,单片机运行梯形图程序(已转换成单片机可执行的语言),控制输出端口的状态。对于用户而言,只需要知道图2.15中的10个外接的端口,至于输入输出电路以及单片机与这些电路的连接,用户无需了解。这样便实现了一个用单片机制作的简单PLC。

3章 系统硬件设计

3.1 硬件设计总述
硬件设计主要是设计外围电路,特别是设计I/O接口。系统硬件设计如图3.1所示。本次设计的硬件部分这要有五个部分:输入电路、输出电路、振荡和复位电路、电源转换电路、串口通信电路。由于本次设计比较简单,只有四个输入和四个输出,没有拓展内存。


图3.1 硬件设计图
3.2 单片机最小系统
PLC控制系统的主要功能是实现各种逻辑和过程控制,因此硬件对输入输出接口有相当高的要求。CPU 是PLC 的核心,起神经中枢的作用,CPU 的运行速度和内存容量是PLC的重要参数,决定着PLC 的工作速度、I/O 数量及软件容量等,因此也限制着控制规模。用单片机实现PLC,其CPU实际上就是单片机,因此选用合适的单片机对于最终实现的PLC的功能影响很大。[8]
本次设计使用的单片机是AT89C52。AT89C52 是美国ATMEL公司生产的低电压,高性能CMOS 8位单片机,片内含8KB的可反复擦写的Flash 只读程序存储器和256 bytes 的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,与标准MCS-51指令系统及8052产品引脚兼容,片内置通用8位中央处理器(CPU)和Flash 存储单元,功能强大AT89C52 单片机适合于许多较为复杂控制应用场合。AT89C52单片机为制作PLC应用提供了灵活且低成本的方案。其最小系统设计如图3.2所示。

图3.2 单片机最小系统
3.2.1 振荡电路
单片机系统里都有晶振,结合单片机内部电路产生单片机所需的时钟频率,单片机晶振提供的时钟频率越高,那么单片机运行速度就越快,单片机的一切指令的执行都需要单片机晶振提供的时钟频率。
图3.3 振荡电路图
单片机晶振的作用是为系统提供基本的时钟信号。通常一个系统共用一个晶振,便于各部分保持同步。本设计使用12MHz的晶体振荡器作为振荡源,由于单片机内部带有振荡电路,所以外部只要连接一个晶振和两个电容即可,电容容量一般在15pF至50pF之间。
3.2.2 复位电路
复位操作是单片机的初始化,其作用是时CPU和系统其他部件都处于一个确定的初始状态,系统从这个状态开始工作。单片机有复位信号引脚RST,用于从外界引入复位信号。单片机的复位电路比较简单,如图3.4所示,RESET接单片机RST引脚。在单片机调试或程序运行时,若遇到死机、死循环或程序“跑飞”等情况,按下复位键S1,单片机就将重新启动。完成复位操作共需24个状态周期。复位结束后,单片机从地址0000H开始执行程序。[9]

图3.4 复位电路

图3.4中,RESET接单片机RST引脚。按键S1按下后,复位端接高电平,实现电路复位。单片机在RST端加一个正脉冲即可实现复位,在系统上电的瞬间,RST与电源电压同电位,随着电容的电压逐渐上升,RST电位下降,于是在RST形成一个正脉冲。
3.3 电源设计
如第二章中所述,PLC等数字系统工作时,需要三种电源:一是输入信号电源;二是内部元器件工作电源;三是负载工作电源。电源模块在整个系统中起十分重要的作用,如果系统没有一个良好的、可靠的电源系统,它是无法正常工作的,因此电源的设计和制造十分重要。[8]
负载工作电源是用来驱动PLC 输出设备(负载)和提供输入信号的,又称用户电源。用户电源的容量由输出设备和PLC 的输入电路决定。由于本系统中 的I/O 电路都有滤波、隔离功能,所以外部电源对PLC 的性能影响不大。用户电源不属于本次设计中的内容。
为了减小设计的复杂性,电源模块为系统运行提供内部工作电源,同时为输入信号提供电源。本设计中的电源设计采用独立的DC24V—DC5V电压转换模块。输入信号是开关量输入,输入电压是24V,电源模块将输入信号的24V电压转换成供单片机工作的5V电压。为了减小电源的数量,在选用继电器时选用了24V的直流继电器。电源模块的电路如图3.5所示。
DC24V—DC5V电压转换模块NMA2405S。NMA系列是独立的直流/直流转换器,开关噪声小,组建电源系统非常简单方便。


图3.5 电源电路

3.4 输入电路
PLC为了提高系统的抗干扰能力,在输入电路部分有各种抗干扰设计。本设计的输入电路也仿照PLC,在信号输入到单片机前进行了滤波处理,采用光电耦合将输入电源与系统电源隔开。图3.6是输入电路逻辑意义上的示意图,图中的INPUT是一个子电路图,里面包含四个相同的输入电路,实际的电路如3.7所示,图3.7中只画出了一路输入,其他输入电路与之相同。图3.6中D1、D2、D3、D4是输入状态指示灯。X0、X1、X2、X3是四个输入端,通过按钮与输入电源24V的负极相连接,按键按下,相应的LED就会亮。IN0、IN1、IN2、IN3接单片机的P0.0、P0.1、P0.2、P0.3。
图3.6 输入电路总图

本设计的输入为开关量输入。输入电路接收工业现场输入设备的开关信号,将信号转换为PLC内部单片机可接受的低电压信号,实现PLC内外信号的电气隔离。本设计的输入信号选用直流输入方式,该方式延时时间较短,还可以直接与光电开关等电子输入设备连接。开关量输入模块的输入信号电压等级选择24V,适用于传输距离较近的场合。为了提高系统的可靠性,需要考虑输入门槛电流的高低,门槛电流越高,抗干扰能力越强,传输距离也越远,文中设计保证信号为真时电流在5到7mA。考虑到控制电路的抗干扰性能,减少设备之间的干扰,开关量输入电路的隔离采用光电耦合器。[8]
图3.7 输入电路

图3.6与图2.2在本质上一样的,是对图2.2的具体化。图3.4中,X0是PLC的一个输入端。D1用于指示该输入点的开关状态。输入信号与单片机之间用光电耦合器TLP521-1隔开。R2是限流电阻,同时与电容C1构成滤波电路,去处高频干扰。估算输入电流约为:(24-2)/4.7=4.7mA,光电耦合器的一次侧驱动电流一般在4.5mA 以上,满足设计要求。R3和C1构成延时电路,一次回路中输入信号有延时。IN0连接单片机的输入端口P0.0。在输入端X0与电源端接入用户输入电路,如图2.2,用户电路中都会设置开关,如果开关闭合,光电耦合器的发光二极管所在的回路导通,光电耦合器的发光二极管发光,光电耦合器的三极管导通,IN0为高电平,D1发光,表示该输入点已经导通。
3.5 输出电路
输出电路用于将单片机内部的低电压信号转换成驱动外部输出设备的开关信号,并且实现PLC内外信号的电气隔离。本设计的输出电路为继电器输出方式,这样可以驱动交流负载,也可以驱动直流负载,使用的电压大小范围较宽,同时承受顺势过电压和过电流的能力较强。与晶闸管输出和晶体管输出相比,唯一的缺点是触电元件动作较慢,寿命较短,不适用于频繁通断的场合。输出电路的输出电流驱动能力必须大于PLC外接设备的额定电流,因此需要根据输出设备的电流大小来确定输出电路的输出电流。[8]

图3.8 输出电路总图

图3.8是输出电路逻辑意义上的示意图,图中的OUTPUT是一个子电路图,里面包含四个相同的输出电路,实际的电路如3.9所示,图3.9中只画出了一路输出,其他输出电路与之相同。图3.8中OUT0、OUT1、OUT2、OUT3接单片机的P1.0、P1.1、P1.2、P1.3。D5、D6、D7、D8是输出状态指示灯。Y0、Y1、Y2、Y3四个输出端,用户电路接在输出端和yCOM之间。


图3.9 输入电路

图3.9与图2.6在本质上一样的,是对图2.6的具体化。5V电源为PLC 的内部电源,24V 电源为开关量输出电源,两个电源是隔离的。图3.7中,Y0是PLC的一个输出端。D1用于指示该输出点的开关状态。输出信号与单片机之间也用光电耦合器TLP521-1隔开。R1是限流电阻。D2用以防止继电器开断时的反向电流。D3是一个齐纳稳压管,是Q1基极和发射极之间电压稳定。OUT0连接单片机的输出端口P1.0。采用汇科继电器HK4100F-24V-SHG,该继电器是小型、小功率继电器,触点形式是常开型,额定电压为DC24V,直流电阻为1Ω,吸合电流为2A,释放电流也为2A,线圈功率为4W,额定工作频率为5Hz。
当OUT0 接口端输出低电平时,经光电耦合器使驱动晶体管Q1导通,继电器K1得电吸合,同时D1发光。当OUT0接口输出高电平,经光电耦合器使Q1 截止,K1释放,D1熄灭。
3.6 串口通信电路
本设计上位机程序下载时采用RS-232C通信接口技术,RS-232C是常用的点对点串行通信技术,采用单端信号传输方式,将PC 机和单片机连接至一起,实现梯形图目标代码的下载。通讯电路如图3.10所示。
图3.10中主要用到了芯片MAX232,该芯片是由美国德州仪器公司(TI)推出的一款兼容RS232标准的芯片。单片机使用的是TTL电平(+5V为高电平,低电平为0V),而计算机的串口为RS-232C电平,其中高电平为-12V,低电平为+12V,RS-232C电平为负逻辑电平。MAX232 就是用来进行电平转换的。该器件包含两个驱动器、两个接收器。它的的9、10、11、12 引脚是TTL 电平端,用来连接单片机;7、8、13、14引脚是接PC机的。

图3.10 串口通信电路

在图3.10中,D9、D10两个发光二极管用来指示此时是否有通信正在进行。串口通信的数据传输过程如下:MAX232的10脚T2IN接单片机TXD端P3.1,TTL电平从单片机的TXD端发出,经过MAX232转换为RS-232电平后从MAX232的7脚T2OUT发出,再连接到系统板上的串口座的第2脚RXD,至此计算机端接收到数据。PC机发送数据时从PC机串口座上的第3脚TXD端发出数据,再逆向流向单片机的RXD端P3.0接收数据。

4章 系统软件设计

4.1 系统程序结构
一个完整的PLC系统程序流程图如图4.1所示,该图是对图2.8的简化。本设计的软件部分主要是模仿PLC的循环工作。输入采样程序和输出程序对任何应用程序都是一样的,这部分属于系统程序,但梯形图处理处理程序需要针对不同的应用编写不同的程序。

                                 

图4.1 系统程序流程图

本设计的编程语言用了C语言和汇编语言两种。汇编语言的执行效率要比C语言高,但可读性比较差。C语言编程简洁,可读性好,但C语言会占用更多的内存资源。
C语言程序含有六个文件:“IO.h”、“timer_counter.h”、“main.c”、“functions.c”、“timer_counter.c”和“process.c”。头文件“IO.h”是对输入输出端口以及输入输出端口映像寄存器的声明。头文件“timer_counter.h”是定时器和计数器的声明,定时器和计数器的定义在C文件“timer_counter.c”中。C文件“main.c”是系统的主程序。C文件“functions.c”中是初始化程序、输入程序、输出程序等的具体实现。C文件“process.c”是用户编写不同控制程序的文件,该文件中内容需要用户根据梯形图程序来填写,其他五个文件不需要用户关心,用户只需要了解一些接口即可。这种设计使用户只要关注如何将梯形图程序转换成C语言,而这种转换往往相对比较简单。
汇编语言程序只有一个文件,含有三个个部分:预定义部分,系统函数部分和用户程序部分。预定义部分是对输入输出端口以及输入输出端口映像寄存器的定义,还包括计数器和定时器的定义。系统程序部分包括主函数,输入/输出函数,定时器程序个计数器程序。用户程序是供用户根据梯形图程序填写的部分。
4.2 系统主程序
系统主程序是主要是模拟PLC的循环工作方式。主程序中调用了四个函数:initi()是初始化程序,getIn()是输入采样程序,process()是用来翻译梯形图程序的梯形图处理程序,getOut()是输出刷新程序。这四个程序的具体定义见本章的4.3、4.4、4.8和4.5。
主程序如下:
void main()
{
   initi();                           
   while(1)
   {
                 getIn();                           
                 process();            
                 getOut();                  
  }
}

汇编程序如下
Main:
                     ACALL Initi                                                      
Loop: ACALL GetIn                                                      
                 LCALL Process                                         
                 ACALL GetOut                                         
                 SJMP Loop
汇编语言中的Initi是初始化程序,GetIn是输入采样程序,Process是用来翻译梯形图程序的梯形图处理程序,GetOut是输出刷新程序。这四个程序的具体定义见本章的4.3、4.4、4.8和4.5。
由以上的程序可以发现,用单片机实现PLC的循环扫描过程,在程序上比较容易实现,结构清晰,易于理解。主程序中各个子函数的具体定义见本章以下各节内容。
4.3 初始化程序
初始化程序是在系统进入循环扫描所必须的预处理。本设计的初始化化程序主要完成以下一些工作:输入、输出初始化,设置所有定时器的时间基数,定时器初始化、计数器初始化化。C语言程序如下。
void initi()
{
              P0=0x00;               
              P1=0xFF;                                         
              TMOD=0x01;            
              TH0=0x3C;
              TL0=0x0B0;            

              EA=1;
              ET0=1;

              initi_timer();            
              initi_counter();
              TR0=1;
}
initi_timer()是定时器初始化程序,initi_counter()是计数器初始化程序。如本章开始所述,把这两个函数定义放在在C文件"process.c"中是为了方便用户,用户在编写用户处理程序时可能会使用定时器和计数器,这就需要对定时器和计数器进行初始化,把这两个程序和用户处理程序放在一个文件中,使用户只需要关注一个文件,专注于梯形图程序的转换。
汇编程序如下:
Initi:              
                            MOV                SP,                            #78H
    MOV               P0,                            #00H               
       MOV               P1,                            #0FFH                             
                            MOV               TMOD,              #01H            
                            MOV               TH0,              #3CH
                            MOV               TL0,              #0B0H            
                            SETB   EA
                            SETB              ET0

                            LCALL  Initi_Timer
                            LCALL  Initi_Counter

                            SETB   TR0
                            RET
Initi_Timer和Initi_Counter分别是定时器初始化程序和计数器初始化程序。
定时器程序和计数器程序见本章的4.6和4.7。
4.4 输入程序
输入程序用以检测四个输入点的开关状态。程序首先把四个输入映像寄存器清零,然后依次检测四个输入端口,如果检测到该输入端为高电平,则延时10毫秒,主要用于去除按键抖动,如果延时10毫秒之后,再次检测到得该输入端仍为高电平,则将该输入点的映像寄存器置1,否则置0。扫描得到的输入映像寄存器的不同状态将在用户程序中使用。In0、In1、In2和In3分别代表单片机的四个输入端口P0.0、P0.1、P0.2和P0.3。InMap0、InMap1、InMap2和InMap3分别是四个输入端口的映像存储器,每个映像存储器占一位存储空间。定义映像存储器实际上也有效地防止了输入信号的干扰,提高了系统的抗干扰能力。输入程序如下:
void getIn()
{
              InMap0=0;
              InMap1=0;
              InMap2=0;
              InMap3=0;

              if(In0)
              {
                            delay10ms();
                            if(In0)
                                          InMap0=1;
              }

              if(In1)
              {
                            delay10ms();
                            if(In1)
                                          InMap1=1;
              }

              if(In2)
              {
                            delay10ms();
                            if(In2)
                                          InMap2=1;
              }

              if(In3)
              {
                            delay10ms();
                            if(In3)
                                          InMap3=1;
              }
}
汇编程序如下:
GetIn:                              
                  CLR InMap0
                            CLR InMap1
                            CLR InMap2
                            CLR InMap3

                            JNB                In0,              CHK1
                            LCALL                KT10MS
                            JNB                In0,              CHK1
                            SETB               InMap0              

   CHK1: JNB                In1,              CHK2
                   LCALL                KT10MS
                   JNB                In1,              CHK2
                   SETB               InMap1

   CHK2: JNB                In2,              CHK3
                            LCALL                KT10MS
                            JNB                In2,              CHK3
                            SETB               InMap2

   CHK3: JNB                In3,              EndCHK
                            LCALL                KT10MS
                            JNB                In3,              EndCHK
                            SETB               InMap3

   EndCHK:RET
4.5  输出程序
输出程序比较简单,在每个扫描周期,都需要把输出映像寄存器的值赋给输出端,即所谓的输出刷新。Out0、Out1、Out2和Out3分别代表单片机的四个输出端口P1.0、P1.1、P1.2和P1.3。OutMap0、OutMap1、OutMap2和OutMap3分别是四个输出端口的映像存储器,每个映像存储器占一位存储空间。输出程序如下:
void getOut()
{
              Out0=~OutMap0;
              Out1=~OutMap1;
              Out2=~OutMap2;
              Out3=~OutMap3;
}
汇编程序如下:
GetOut:            
                            MOV               C,                            OutMap0
                            CPL              C                                                      
                            MOV               Out0,              C                                                                     
                            MOV               C,                            OutMap1
                            CPL              C
                            MOV               Out1,              C

                            MOV               C,                            OutMap2
                            CPL              C
                            MOV              Out2,              C

                            MOV               C,                            OutMap3
                            CPL              C
                            MOV               Out3,              C
                            RET
特别要注意的是,本设计在输出时是低电平表示输出有效(见图3.9),是负逻辑,为了在梯形图处理程序中减小用户的负担,在梯形图处理程序中使用易于理解的正逻辑,只在输出时对所有的映像寄存器取反,但是这里的取反并不是让映像存储器里的值取反,这样会破坏用户编写的程序,而是将映像存储器相反的值赋给相应的输出端。
4.6  定时程序
PLC中的定时器代表延时继电器的功能,通常可以有多个,考虑到单片机内存资源有限,本设计中定义了10个定时器。定时器需要一个统一的时钟,用单片机片内的T0来作统一的时钟。T0每0.05秒中断一次,T0的设置在初始化程序中。因此定时器程序包两个部分,一个是定时中断服务程序,另一个是定时器逻辑指令程序。
4.6.1 定时器的定义
定时器有四个部分组成:定时器逻辑位,初始值,定时器计数器,触发启动标志。定时器如果用C语言的结构体定义比较容易理解。定时器的结构体定义如下。
struct  tim
{
              Bit DT;                                                             //定时器逻辑位(溢出标志)
              unsigned int K;                                             //初值
              unsigned int TC;                               //定时器计数器
              Bit ST;                                                                      //触发启动标志
} timer[10];
定时器的计数器占两个字节,最大值是65535,由于每中断一次,计数器加1,因此定时器的最长定时时间为3276.75秒。
4.6.2定时中断服务程序
定时中断服务程序的流程图如4.2所示。
图4.2 中断服务程序流程图[10]

根据流程图,写出C程序如下。
void interT0() interrupt 1
{
                unsigned char i;

                TR0=0;
                TH0=0x3c;
                TL0=0xb0;
                for(i=0;i<10;i++)                                                           
    {
                              if(timer[ i].ST)
                                            timer.TC++;            
                }
                TR0=1;
}
汇编程序如下:
IT0Int:   CLR               TR0
                              PUSH               PSW
                              PUSH               ACC
                              MOV               TH0,              #3CH
                              MOV               TL0,              #0B0H            
                              JNB               ST0,                            Next1
                              INC               TC0_L
                              MOV A , TC0_L                                                                        
        JNZ    Next1
        INC               TC0_H
  Next1:  JNB               ST1,                            Next2
                                INC               TC1_L
                              MOV A , TC1_L
                              JNZ    Next2
          INC               TC1_H
  Next2:  JNB               ST2,                            Next3
                                INC               TC2_H
                              MOV A , TC2_L
                              JNZ    Next3
                              INC               TC2_L
  Next3:  JNB               ST3,                            Next4
                                INC               TC3_L
                              MOV A , TC3_L
                              JNZ    Next4
          INC               TC3_H
  Next4:  JNB               ST4,              Next5
                                  INC               TC4_L
                                MOV A , TC4_L
                                JNZ    Next5
          INC               TC4_H
  Next5:  JNB               ST5,              Next6
                                INC               TC5_L
                              MOV A , TC5_L
                              JNZ    Next6
          INC               TC5_H
  Next6:  JNB               ST6,                            Next7
          INC               TC6_L
                              MOV A , TC6_L
                              JNZ    Next7
          INC               TC6_H
  Next7:  JNB               ST7,                            Next8            
                                INC               TC7_L
                              MOV A , TC7_L
                              JNZ    Next8
          INC               TC7_H
  Next8:  JNB               ST8,                            Next9
                                INC               TC8_L
                              MOV A , TC8_L
                              JNZ    Next9
          INC               TC8_H
  Next9:  JNB               ST9,              EndInt               
                     INC               TC9_L
                              MOV A , TC9_L
                              JNZ    EndInt
          INC               TC9_H
  EndInt: POP ACC
                              POP PSW
                              SETB TR0
                              RETI
4.6.3定时器逻辑指令程序
定时器逻辑指令程序中需要注意触发启动标志何时打开。流程图如图4.3所示。
图4.2 定时器程序流程图[10]

根据以上的流程图写出的C语言程序如下。
void  time(unsigned char n,bit in)
{
              if(in)
                            {
                                          if(timer[n].ST)
                                          {
                                                        if(timer[n].TC==timer[n].K)               
                                                        {
                                                                      timer[n].DT=1;                                          
                                                                      timer[n].ST=0;
                                                                      timer[n].TC=0;
                                                        }
                                          }
                                          else
                                          {
                                                        if(timer[n].DT!=1)
                                                                      timer[n].ST=1;               
                                          }
                            }
              else
                            {
                                          timer[n].DT=0;
                                          timer[n].ST=0;
                                          timer[n].TC=0;
                            }
}
程序中的n是定时器的编号,有效值是0到9,in是当前的逻辑运算值。
汇编程序需要对分别写出每个定时器的逻辑指令程序,但它们都是相同的。下面定时器0为例,写出汇编程序如下。汇编程序中当前逻辑运算值在位累加器C中。
Tim0:                            JNC                            Off0
                                          JNB                            ST0,              Open0

                                          MOV                            A,                            TC0_L                                         
                                          CJNE    A,                            K0_L,              Exit0
                                          MOV                            A,                            TC0_H
                                          CJNE    A,                            K0_H,              Exit0
                                          SETB              DT0                                                                        
                                          SJMP    Rest0

              Open0:              JB                            ST0,                            Exit0
                                          JB                            DT0,                            Exit0
                                          SETB              ST0                                                                                   
                                          RET

              Off0:              CLR                            DT0                           
              Rest0:              CLR                            ST0                           
                                          MOV     TC0_H,                            #00H                              
                                          MOV     TC0_L,                            #00H

              Exit0:              RET
4.6.4定时器初始化
用户需要对用到得定时器进行初始化,C语言初始化程序如下。程序中已对初始化的方法做了详细的说明。
void initi_timer()
{
              /*timer[n].K=t/0.05;*/
}
程序中的n是使用的定时器编号(0-9)。t是定时的时间,最长定时时间为3276.75秒。
汇编语言定时器的初始化方法如下。
Initi_Timer:              /*              MOV              Kn_L,              #Low            
                         MOV              Kn_H,              #High*/            
                         RET
程序中Low=t/0.05%256,High=t/0.05/256。
4.7  计数程序
S7-200中的计数器有加计数器、减计数器和加减计数器。本设计的计数器属于加计数器。S7-200中的计数器如图4.3所示。当计数器的复位端R断开,且输入脉冲CU检测到输入信号正跳变时当前值加1,直到达到PV端设定值时,计数器的逻辑位置位。
图4.3 加计数器
4.7.1 计数器的定义
下面的结构体定义了计数器的结构。
struct  ct
{
              Bit Cnt;                                                        //计数器逻辑位(溢出标志)
              unsigned int PV;                            //初值
              unsigned int CT;                            //计数器
              Bit RST;                                          //复位标志
} counter[10];
定义了10个计数器,计数器初始值最大为65535。
4.7.2计数器程序的实现
根据S7-200中的加计数器,计数器的流程图如图4.4所示。
图4.4 计数器程序流程图


根据以上的流程图写出计数器的C语言程序如下。
void count(unsigned char n,bit in)
{
              if(!counter[n].RST)
                            {
                                          if(in)
                                                        {
                                                                      if(!counter[n].Cnt)
                                                                                    counter[n].CT++;
                                                                      if(counter[n].CT==counter[n].PV)
                                                                      {
                                                                                    counter[n].Cnt=1;
                                                                                    counter[n].CT=0;
                                                                      }
              }
           else
           counter[n].Cnt=0;
                                                        }
                            }
              else
              {
                                          counter[n].Cnt=0;
                                          counter[n].CT=0;
              }
}
程序中的n是计数器的编号,有效值是0到9,in是当前的逻辑运算值。
汇编程序需要对分别写出每个计数器的程序,但它们都是相同的。下面计数器0为例,写出汇编程序如下。汇编程序中当前逻辑运算值在位累加器C中。
COUNT0: JB              RST0,Reset0                           
                              JNC   CExit0                                         
                              JB    C0,  End0

                              INC   C0_L                              
                              MOV A , C0_L
                              JNZ    CN0
                              INC   C0_H

              CN0: MOV              A,                            C0_L                                         
                              CJNE    A,                            PV0_L,              End0
                              MOV                  A,                            C0_H
                              CJNE    A,                            PV0_H,              End0                           
                              SETB               C0                                                      
                              MOV                  C0_L,  #0                                         
                              MOV   C0_H,  #0
                              RET

  Reset0: MOV                C0_L,   #0                           
                              MOV   C0_H,  #0
CExit0:  CLR   C0
   End0:  RET
4.7.3计数器初始化
用户需要对用到得计数器进行初始化,计数器的初始化很简单,C语言初始化程序如下。
void initi_counter()
{            
              /*counter[n].PV=;*/                                                                     
}
程序中的n是使用的计数器编号(0-9)。设置计数器初始值,最大值为65535。
汇编语言定时器的初始化方法如下。
Initi_Counter: /*              MOV              PVn_L,              #Low                                                                                   
             MOV              PVn_H,              #High*/            
                        RET                                                                     
程序中Low=PV%256,High=PV/256。
4.8 梯形图处理程序
以上的的程序都属于系统程序,用户是不需要关心的。只有梯形图处理程序是用户需要关注的。梯形图处理程序需要用户根据梯形图程序编写,因此梯形图处理程序是不完整的。梯形图处理程序如下。
void process()
{
//先定义辅助继电器
//用户根据梯形图在此填写程序
}
汇编程序如下:
Process:            
/*用户根据梯形图在此填写程序*/
         RET
下面举一个例子。
现设计一个使用一个按钮控制电机的启、停,第一次按动按钮,电机启动,第二次按动按钮,电机停止转动。梯形图程序如图4.2所示。


图4.2 用户处理程序举例

通过第二章的分析可知,把图4.2转换成C语言或者汇编语言是很容易的。假设按扭使用X0接口,电机使用Y0接口(见图2.15)。
在写汇编语言之前要先定义映像寄存器和辅助寄存器:
  M0_0  BIT  26H.1                           
  M0_1  BIT  26H.2            
  M0_2  BIT  26H.3
写出的汇编程序如下:
Process: MOV              C,                            InMap0
                            ANL              C,                            /M0_1
                            MOV              M0_0,              C

                            MOV    C,                            InMap0
                            MOV    M0_1,              C

                            MOV              C,                            M0_0
                            ANL              C,                            OutMap0
                            MOV              M0_2,              C

                            MOV              C,                            M0_0
                            ORL              C,                            OutMap0
                            ANL              C,                            /M0_2
                            MOV              OutMap0,              C

        RET
如果写成C语言则更加容易:
void process()
{
   bit M0_0,M0_1,M0_2;
       M0_0=InMap0&(~M0_1);
       M0_1=InMap0;
       M0_2=M0_0&OutMap0;
       OutMap0=(M0_0|OutMap0)&(~M0_2);
     }




5章 基于Proteus的软件仿真
5.1 Proteus仿真软件简介
Proteus ISIS是英国Labcenter公司开发的电路分析与实物仿真软件。该软件是一款集单片机和SPICE分析于一身的仿真软件,功能极其强大。它运行于Windows操作系统上,可以仿真、分析(SPICE)各种模拟器件和集成电路。
Proteus ISIS的工作界面是一种标准的Windows界面,如图5.1所示。包括:标题栏、主菜单、标准工具栏、绘图工具栏、状态栏、对象选择按钮、预览对象方位控制按钮、仿真进程控制按钮、预览窗口、对象选择器窗口、图形编辑窗口。


图 5.1 Proteus工作界面

该软件的特点是:
(1)实现了单片机仿真和SPICE电路仿真相结合。具有模拟电路仿真、数字电路仿真、单片机及其外围电路组成的系统的仿真、RS232动态仿真、I2C调试器、SPI调试器、键盘和LCD系统仿真的功能;有各种虚拟仪器,如示波器、逻辑分析仪、信号发生器等。
(2)支持主流单片机系统的仿真。目前支持的单片机类型有:68000系列、8051系列、AVR系列、PIC12系列、PIC16系列、PIC18系列、Z80系列、HC11系列以及各种外围芯片。
(3)提供软件调试功能。在硬件仿真系统中具有全速、单步、设置断点等调试功能,同时可以观察各个变量、寄存器等的当前状态,因此在该软件仿真系统中,也必须具有这些功能;同时支持第三方的软件编译和调试环境,如Keil C51等软件。
(4)具有强大的原理图绘制功能。
5.2仿真实验5.2.1 对输入电路的仿真测试
为了验证仿真电路的正确性,减小硬件制作的成本,可以用Proteus先进行仿真验证。在图5.7中,对输入电路中的一路进行了仿真。如图5.2所示,当按键没有按下时,D1不亮,输入到单片机引脚P0.0的输入端IN0的电压为6.96482e-6V,是低电平。

图 5.2 输入电路测试1

在图5.3中,按键已经按下,D1发光,IN0端的电压是4.66026V,是高电平。
模拟情况符合设计的要求。

图 5.3 输入电路测试2
在仿真中发现D1的亮度不是很高,是由于输入回路中电流过小的缘故。D1的导通压降为2V,最大电流为10mA。
5.2.2 对输出电路的仿真测试
图5.3是对输出电路的仿真测试。在图5.9中,当开关SW1接地是,直流电动机转动,稳压管两端的电压稳定在3.20648V。当SW1接高电平时,电动机是不转动的。从仿真测试中可知,输出电路是符合设计要求的。
图 5.4 输出电路测试
5.2.3 多路故障报警系统仿真
为了验证设计的正确性,下面通过一个实例用Proteus软件进行了仿真。
报警是电气自动控制中不可缺少的重点环节,标志的报警功能应该是声光报警。本仿真是一个两路的声光报警系统。系统的仿真原理图如图5.5所示。该系统有四个输入,三个输出。图5.5中的OUTRUT是一个子电路图,里面含有四个相同的输出电路,见图5.6。图5.5中的D5、D6、D7和D8是输出状态指示灯。
图 5.5 声光报警控制系统
图中的SA1和SA2是两个故障输入信号。如果SA1或SA2按下,表示故障发生。当故障发生以后,报警灯会闪烁,同时蜂鸣器鸣响。SB1是故障解除按钮。当操作人员知道故障发生后,按下SB1,蜂鸣器就停止鸣响,报警指示灯从闪烁变为常亮,告诉造作人员哪一路发生了故障。系统还设置了SB2测试按钮,用于平时检测报警指示灯和蜂鸣器的好坏。
图 5.6 仿真输出电路

报警系统的梯形图程序如图5.7所示。
图 5.7 报警系统梯形图程序

根据梯形图写出C程序如下。
为了方便程序阅读,先做一些预处理。
#define SA1 InMap0
#define SA2 InMap1
#define SB1 InMap2
#define SB2 InMap3
#define Q0  OutMap0
#define Q1  OutMap1
#define Q2  OutMap2
#define T0  timer[0].DT
#define T1  timer[1].DT
void initi_timer()
{
              timer[0].K=2/0.05;
              timer[1].K=1/0.05;
}
void process()
{
                bit M0,M1;
              time(0,(SA1|SA2)&(~T1));
              time(1,T0);
              Q0=((T0|M0)&SA1)|SB2;
              Q1=((T0|M1)&SA2)|SB2;
              M0=(SB1|M0)&SA1;
              M1=(SB1|M1)&SA2;
              Q2=(SA1&(~M0))|(SA2&(~M1))|SB2;

}
根据梯形图写出汇编程序如下。
      M0 BIT 26H.0
                            M1 BIT 26H.1
                            SA1 BIT InMap0
                            SA2 BIT InMap1
                            SB1 BIT InMap2
                            SB2 BIT InMap3            
                            Q0 BIT OutMap0
                            Q1 BIT OutMap1
                            Q2 BIT OutMap2

Initi_Timer:              MOV              K0_L,              #40            
                                          MOV              K0_H,              #0
                                          MOV              K1_L,              #20            
                                          MOV              K1_H,              #0
                                          RET

Process: MOV C,SA1
                            ORL C,SA2
                            ANL C,/DT1
                            LCALL Tim0
                            MOV C,DT0
                            LCALL Tim1

                            MOV C,DT0
                            ORL C,M0
                            ANL C,SA1
                            ORL C,SB2
                            MOV Q0,C

                            MOV C,DT0
                            ORL C,M1
                            ANL C,SA2
                            ORL C,SB2
                            MOV Q1,C

                            MOV C,SB1
                            ORL C,M0
                            ANL C,SA1
                            MOV M0,C

                            MOV C,SB1
                            ORL C,M1
                            ANL C,SA2
                            MOV M1,C

                            MOV C,SA1
                            ANL C,/M0
                            MOV 26H.2,C
                            MOV C,SA2
                            ANL C,/M1
                            ORL C,26H.2
                            ORL C,SB2
                            MOV Q2,C            

        RET
5.3仿真总结
上述的仿真实验可以达到预期的效果。说明硬件设计和程序设计是可行的。
仿真中还有一些问题:输入电路在接单片机时,单片机引脚不能检测到高电平,因此仿真中做了简单处理。C程序会出现内存不够的现象,因此在上面的C程序中没有包括计数器。
仿真的结果往往比较理想化,因此并不能代表没有错误。由与没有制作实物,本设计还需要在实践中检验其可靠性。
6章 总结
单片机和PLC都是在工业控制领域有着广泛应用的工业控制装置,它们各有各自的特点。
本设计用AT89C52单片机设计了一个4输入4输出的简单PLC。该PLC含有10个定时器和10个计数器,每个定时器的最长定时时间为3276.75秒,每个计数器的最大计数值为65535。该PLC的输入方式为直流开关量,输入电压为24V。输出采用继电器输出方式,继电器的额定电压为DC24V,吸合电流为2A,线圈功率为4W。为了提高系统的抗干扰能力,输入输出电路中都使用了光电耦合器。该PLC具有与计算通讯能力,可以在计算机上下载程序。
最终完成了原来图和PCB图的绘制,也对设计的正确性通过Proteus仿真进行了验证。
但仿真的结果往往比较理想化,因此并不能代表没有错误。由与没有制作实物,本设计还需要在实践中检验其可靠性。
在设计时,为了简化设计,没有拓展单片机内存,梯形图程序稍微复杂时,用C语言编写的程序往往会超出内存空间。本设计在程序中没有自诊断功能。对一些简单的控制,在仿真时本设计是可行的。为了能满足复杂的控制需要,在功能上还可以进行拓展:
  • 增加输人、输出接点的数量
  • 增加不同的输入方式和输出方式。
  • 为适应工业环境的要求, 就要有极为可靠的抗干扰措施
3.加大负载能力, 以满足工业控制对象的一般需要。
4.增加处理模拟量的能力, 以满足模拟量的控制濡要。
5.增加通讯能力, 以满足控制系统网络的需要。
6.拓展单片机的内存,使制作的PLC能够运行更加复杂的程序。
7.增加更加丰富的人机接口,比如拨盘预置程序输入预置值,LCD显示工作状态等。
由于软件的扩充, 扫描时间必然加长, 所以就要提高运行速。由于硬件的扩充, 体积必然增大,因此要有合理的结构。硬件的拓充和功能的增加,又对软件设计提出了更高的要求,软件系统要更加合理。
用单片机制作PLC的另外一个研究方向是开发出一种将梯形图直接转化成单片机可执行的二进制文件的软件。这样用户只需要根据控制需要,设计出自己的梯形图程序,然后直接把梯形图程序通过软件转换成二进制文件,用户不必要写C语言程序或者汇编程序。这是一个值得研究的课题。


致谢
在毕业论文即将完成之际,我要衷心感谢甘英俊老师在毕业设计期间给予的指导和帮助!甘老师工作繁忙,但依然十分关心我们的毕业设计,每周都抽出时间悉心指导我们。甘老师渊博的知识和严谨的工作作风深深地影响了我。
同时也要感谢大学期间所有的任课老师,他们教授的知识是我大学期间获得的宝贵财富。



附录A  系统原理图

B  系统PCB图


全部资料51hei下载地址:
单片机制作PLC.rar (635.07 KB, 下载次数: 46)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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