让榨汁机定时工作(C#+PLC)

买了自加热的榨汁机每天补充营养是件好事,但是为此早起一个小时却划不来。如果为了节省时间,早上用微波炉加热昨晚做好的豆汁,口感却不怎么好。怎么办?买定时加热的榨汁机,估计价钱会很高,不过市面上好像也没有带这种功能的。

正好这段时间对硬件比较感兴趣,所以抽时间用西门子PLC224实现了该功能(一个PLC一两千元,用PLC控制好像有点高射炮打蚊子--大材小用,建议最好用单片机或.Net Micro Framework实现,这样成本会很低)。

基本思路:

1、由于PLC外部没有显示和控制接口,所以需要在PC机上编写一个程序,用来设定定时时间和间隔。此外由于PLC的时钟精度较低,长时间运行偏差较大,所以还得提供一个校时功能。

2、PLC程序相对比较简单,只要用当前时间和设定时间进行比较,时间到,则Q0.0输出信号,由此驱动继电器工作,过了时间间隔,则停止输出。

3、PC和PLC通信部分,由于PLC原生支持PPI协议,可以采用我以前编写的西门子PPI控件进行访问。当然也可以采用Modbus Rtu模式进行通信,不过需要PLC程序添加Modbus Rtu Slave库,这样增大了PLC程序空间,由于Modbus协议为公开协议,可以在PC上自行编写Modbus Rtu读写程序,不过也可以采用我编写的Modbus Rtu控件进行通信控制。

实际接线图如下:

 

让榨汁机定时工作(C#+PLC)_第1张图片

 

PLC程序如下(语句表)

TITLE=榨汁机控制程序|[叶帆工作室]http://yfsoft.blog.51cto.com

Network 1

// 初始化

LD     SM0.1

MOVB   16#55, VB101                //复位初始状态

Network 2

// 设定日期

LDB=   VB100, 16#AA

MOVB   16#55, VB100

//VB110 年 VB111 月 VB112 日 VB113 时 VB114 分 VB115 秒 VB117 星期

TODW   VB110                       //设置时钟

Network 3

// 读取日期(1s刷新一次)

LD     SM0.5

EU

TODR   VB120                       //读取时钟

Network 4

// 判断是否开始输出

LDB=   16#55, VB101                //没有输出

AB=    VB123, VB130                //时

AB=    VB124, VB131                //分

AB=    VB125, VB132                //秒

EU

S      Q0.0, 1                     //Q0.0输出

MOVB   16#AA, VB101                //置位状态

Network 5

// 判断是否停止输出

LDB=   16#AA, VB101                //没有输出

AB=    VB123, VB140                //时

AB=    VB124, VB141                //分

AB=    VB125, VB142                //秒

EU

R      Q0.0, 1                     //Q0.0输出

MOVB   16#55, VB101                //复位状态

 

PC程序运行后的界面:

 

 

 

相关代码如下:

  
  
  
  
  1. using System;  
  2.  
  3. using System.Collections.Generic;  
  4.  
  5. using System.ComponentModel;  
  6.  
  7. using System.Data;  
  8.  
  9. using System.Drawing;  
  10.  
  11. using System.Text;  
  12.  
  13. using System.Windows.Forms;  
  14.  
  15. using System.Text.RegularExpressions;  
  16.  
  17.    
  18.  
  19. namespace PPI_Test  
  20.  
  21. {  
  22.  
  23.     public partial class frmMain : Form  
  24.  
  25.     {  
  26.  
  27.         public frmMain()  
  28.  
  29.         {  
  30.  
  31.             InitializeComponent();  
  32.  
  33.         }  
  34.  
  35.    
  36.  
  37.         private void frmMain_Load(object sender, EventArgs e)  
  38.  
  39.         {  
  40.  
  41.             //"×××公司"    '已注册的公司名称  
  42.  
  43.             axS7_PPI1.InitRegCompany("叶帆测试");              
  44.  
  45.             axS7_PPI1.bps = PPIV2.PPIBps.mb9600;  
  46.  
  47.             axS7_PPI1.CheckOut = PPIV2.PPICheckOut.mbEven;      
  48.  
  49.             if (axS7_PPI1.OpenPort(1, 2, 1024, 512) != 0)  
  50.  
  51.             {  
  52.  
  53.                 MessageBox.Show("打开串口失败!");  
  54.  
  55.             }  
  56.  
  57.         }  
  58.  
  59.    
  60.  
  61.         private void frmMain_FormClosed(object sender, FormClosedEventArgs e)  
  62.  
  63.         {  
  64.  
  65.             axS7_PPI1.ClosePort();  
  66.  
  67.         }  
  68.  
  69.           
  70.  
  71.         /// <summary>  
  72.  
  73.         /// 登录  
  74.  
  75.         /// </summary>  
  76.  
  77.         /// <param name="sender"></param>  
  78.  
  79.         /// <param name="e"></param>  
  80.  
  81.         private void btnLogin_Click(object sender, EventArgs e)  
  82.  
  83.         {  
  84.  
  85.             if (axS7_PPI1.PlcLogin(byte.Parse(txtFixAddr.Text)) == 0)  
  86.  
  87.             {  
  88.  
  89.                 txtFixAddr.BackColor = Color.Green;  
  90.  
  91.             }  
  92.  
  93.             else 
  94.  
  95.             {  
  96.  
  97.                 txtFixAddr.BackColor = Color.Red;  
  98.  
  99.             }  
  100.  
  101.         }  
  102.  
  103.    
  104.  
  105.         //运行  
  106.  
  107.         private void btnRun_Click(object sender, EventArgs e)  
  108.  
  109.         {  
  110.  
  111.             int intAddr = int.Parse(txtFixAddr.Text);  
  112.  
  113.    
  114.  
  115.             long lngRet = axS7_PPI1.PlcRun(intAddr);  
  116.  
  117.             if (lngRet == 0)  
  118.  
  119.             {  
  120.  
  121.                 MessageBox.Show("开始运行!");  
  122.  
  123.             }  
  124.  
  125.             else if (lngRet == 4)  
  126.  
  127.             {  
  128.  
  129.                 MessageBox.Show("PLC拨码开关在停止位置!");  
  130.  
  131.             }  
  132.  
  133.             else 
  134.  
  135.             {  
  136.  
  137.                 MessageBox.Show("操作失败!");  
  138.  
  139.             }  
  140.  
  141.         }  
  142.  
  143.    
  144.  
  145.         //停止  
  146.  
  147.         private void btnStop_Click(object sender, EventArgs e)  
  148.  
  149.         {  
  150.  
  151.             int intAddr = int.Parse(txtFixAddr.Text);  
  152.  
  153.             long lngRet = axS7_PPI1.PlcStop(intAddr);  
  154.  
  155.             if (lngRet == 0)  
  156.  
  157.             {  
  158.  
  159.                 MessageBox.Show("停止运行!");  
  160.  
  161.             }  
  162.  
  163.             else 
  164.  
  165.             {  
  166.  
  167.                 MessageBox.Show("操作失败!");  
  168.  
  169.             }  
  170.  
  171.         }  
  172.  
  173.    
  174.  
  175.         //读取日期  
  176.  
  177.         private void btnGetDate_Click(object sender, EventArgs e)  
  178.  
  179.         {  
  180.  
  181.             int intAddr = int.Parse(txtFixAddr.Text);  
  182.  
  183.             object vData = new object();  
  184.  
  185.    
  186.  
  187.             if (axS7_PPI1.ReadData(120, ref vData, 6, PPIV2.PPILEN.PPI_B, PPIV2.PPITYPE.PPI_V, intAddr) == 0)  
  188.  
  189.             {  
  190.  
  191.                 Int32[] intData = (Int32[])vData;  
  192.  
  193.                 lblDate.Text ="20"+ intData[0].ToString("X2") + "-" + intData[1].ToString("X2") + "-" + intData[2].ToString("X2") + " " +  
  194.  
  195.                                intData[3].ToString("X2") + ":" + intData[4].ToString("X2") + ":" + intData[5].ToString("X2");  
  196.  
  197.             }  
  198.  
  199.             else 
  200.  
  201.             {  
  202.  
  203.                 lblDate.Text = "读日期错!";  
  204.  
  205.             }  
  206.  
  207.         }  
  208.  
  209.         private void btnSetDate_Click(object sender, EventArgs e)  
  210.  
  211.         {  
  212.  
  213.             int intAddr = int.Parse(txtFixAddr.Text);  
  214.  
  215.             Int32[] intData = new Int32[8];  
  216.  
  217.             DateTime dt = DateTime.Now.AddSeconds(1);  
  218.  
  219.             intData[0] = Convert.ToInt32("0x" + (dt.Year - 2000).ToString(), 16);  
  220.  
  221.             intData[1] = Convert.ToInt32("0x" + dt.Month.ToString(), 16);  
  222.  
  223.             intData[2] = Convert.ToInt32("0x" + dt.Day.ToString(), 16);  
  224.  
  225.             intData[3] = Convert.ToInt32("0x" + dt.Hour.ToString(), 16);  
  226.  
  227.             intData[4] = Convert.ToInt32("0x" + dt.Minute.ToString(), 16);  
  228.  
  229.             intData[5] = Convert.ToInt32("0x" + dt.Second.ToString(), 16);  
  230.  
  231.             intData[7] = (int)dt.DayOfWeek;  
  232.  
  233.    
  234.  
  235.             //写日期时间  
  236.  
  237.             if (axS7_PPI1.WriteData(110, intData, 8, PPIV2.PPILEN.PPI_B, PPIV2.PPITYPE.PPI_V, intAddr) != 0)  
  238.  
  239.             {  
  240.  
  241.                 lblDate.Text = "设置日期错!";  
  242.  
  243.                 return;  
  244.  
  245.             }             
  246.  
  247.    
  248.  
  249.             //写设置标志  
  250.  
  251.             intData[0] = 0xAA;  
  252.  
  253.             if (axS7_PPI1.WriteData(100, intData, 1, PPIV2.PPILEN.PPI_B, PPIV2.PPITYPE.PPI_V, intAddr) != 0)  
  254.  
  255.             {  
  256.  
  257.                 lblDate.Text = "设置标志错!";  
  258.  
  259.             }  
  260.  
  261.         }  
  262.  
  263.    
  264.  
  265.         private void btnConfig_Click(object sender, EventArgs e)  
  266.  
  267.         {  
  268.  
  269.            if (!Regex.IsMatch(txtTimeStart.Text, @"^(0?([0-9])|1[0-9]|2[0-3]):(0?([0-9])|[1-5][0-9]):(0?([0-9])|[1-5][0-9])$"))  
  270.  
  271.            {  
  272.  
  273.                MessageBox.Show("时间格式不匹配,正确格式为:HH:MM:SS");  
  274.  
  275.                return;  
  276.  
  277.            }             
  278.  
  279.            if (!Regex.IsMatch(txtSpan.Text, @"^[^0]\d?\d?$"))  
  280.  
  281.            {  
  282.  
  283.                MessageBox.Show("时间间隔不正确,范围:1-999分钟");  
  284.  
  285.                return;  
  286.  
  287.            }                
  288.  
  289.            DateTime dt = DateTime.Parse(txtTimeStart.Text);  
  290.  
  291.            int intAddr = int.Parse(txtFixAddr.Text);  
  292.  
  293.            Int32[] intData = new Int32[3];  
  294.  
  295.    
  296.  
  297.            //写开始时间  
  298.  
  299.            intData[0] = Convert.ToInt32("0x" + dt.Hour.ToString(), 16);  
  300.  
  301.            intData[1] = Convert.ToInt32("0x" + dt.Minute.ToString(), 16);  
  302.  
  303.            intData[2] = Convert.ToInt32("0x" + dt.Second.ToString(), 16);  
  304.  
  305.            if (axS7_PPI1.WriteData(130, intData,3, PPIV2.PPILEN.PPI_B, PPIV2.PPITYPE.PPI_V, intAddr) != 0)  
  306.  
  307.            {  
  308.  
  309.                lblDate.Text = "写开始时间错!";  
  310.  
  311.                return;  
  312.  
  313.            }           
  314.  
  315.            //写停止时间  
  316.  
  317.            dt = dt.AddMinutes(int.Parse(txtSpan.Text));  
  318.  
  319.            intData[0] = Convert.ToInt32("0x" + dt.Hour.ToString(), 16);  
  320.  
  321.            intData[1] = Convert.ToInt32("0x" + dt.Minute.ToString(), 16);  
  322.  
  323.            intData[2] = Convert.ToInt32("0x" + dt.Second.ToString(), 16);  
  324.  
  325.            if (axS7_PPI1.WriteData(140, intData, 3, PPIV2.PPILEN.PPI_B, PPIV2.PPITYPE.PPI_V, intAddr) != 0)  
  326.  
  327.            {  
  328.  
  329.                lblDate.Text = "写停止时间错!";  
  330.  
  331.                return;  
  332.  
  333.            }    
  334.  
  335.         }  
  336.  
  337.     }  
  338.  
  339. }  
  340.  

当然这只是一个初级应用,如果我们扩展一下,用GPRS技术(参见我写的文章:让智能手机和居家电脑互联互通(WM6 GPRS)),我们可以用手机远程操控榨汁机工作,这样我们就可以在下班前让榨汁机工作。不过这得需要有一台能上网的电脑,编一个TCP服务程序,来接收手机发出的命令。这样PLC程序其实可以不用编写了,我们直接用西门子PPI控件操作PLC的Q0.0。当然如果系统中加入了PC,这样PLC似乎就可以免了,我们可以用串口的RTS管脚去驱动5v的继电器,由继电器来驱动榨汁机工作。

注:由于榨汁机并不是接通电源就可以工作(因这一点没有提前考虑到,差点让我的控制计划流产),所以我用了一个小窍门,先用一个小东西预先按在所需要的按钮上(参见第一张图上的黄色方块),这样一上电,榨汁机就可以正常工作了。

 

 

本文出自 “叶帆工作室” 博客,转载请与作者联系!

你可能感兴趣的:(职场,休闲,PLC,榨汁机)