让榨汁机定时工作(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控件进行通信控制。

实际接线图如下:

 

 

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的继电器,由继电器来驱动榨汁机工作。

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

 








本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/323890,如需转载请自行联系原作者

相关文章
|
2月前
|
JavaScript C#
【傻瓜级JS-DLL-WINCC-PLC交互】7.​C#直连PLC并读取PLC数据
【傻瓜级JS-DLL-WINCC-PLC交互】7.​C#直连PLC并读取PLC数据
153 0
艾伟_转载:让榨汁机定时工作(C#+PLC)
买了自加热的榨汁机每天补充营养是件好事,但是为此早起一个小时却划不来。如果为了节省时间,早上用微波炉加热昨晚做好的豆汁,口感却不怎么好。怎么办?买定时加热的榨汁机,估计价钱会很高,不过市面上好像也没有带这种功能的。
1096 0
|
2月前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
|
2月前
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。
|
14天前
|
存储 C# 开发者
C# 编程基础:注释、变量、常量、数据类型和自定义类型
C# 编程基础:注释、变量、常量、数据类型和自定义类型
15 1
|
2月前
|
开发框架 .NET Java
探索 C#编程的奥秘与魅力
【4月更文挑战第20天】C#是微软开发的现代、面向对象的编程语言,以其简洁语法、强大功能和跨平台支持脱颖而出。它支持自动垃圾回收、泛型、委托、LINQ,并广泛应用于桌面、Web、移动和游戏开发。C#拥有活跃的开发者社区和丰富的资源,是Unity游戏开发的首选语言。随着.NET Core,C#可在多个操作系统上运行,持续创新,未来发展潜力巨大。
|
2月前
|
存储 安全 网络安全
C#编程的安全性与加密技术
【4月更文挑战第21天】C#在.NET框架支持下,以其面向对象和高级特性成为安全软件开发的利器。本文探讨C#在安全加密领域的应用,包括使用System.Security.Cryptography库实现加密算法,利用SSL/TLS保障网络传输安全,进行身份验证,并强调编写安全代码的重要性。实际案例涵盖在线支付、企业应用和文件加密,展示了C#在应对安全挑战的同时,不断拓展其在该领域的潜力和未来前景。
|
2月前
|
人工智能 C# 云计算
C#编程的未来发展趋向
【4月更文挑战第21天】C#编程未来将深化跨平台支持,强化云计算与容器技术集成,如.NET Core、Docker。在AI和ML领域,C#将提供更丰富框架,与AI芯片集成。语言和工具将持续创新,优化异步编程,如Task、async和await,提升多核性能。开源生态的壮大将吸引更多开发者,共创更多机遇。
|
2月前
|
程序员 C#
C#编程中的面向对象编程思想
【4月更文挑战第21天】本文探讨了C#中的面向对象编程,包括类、对象、封装、继承和多态。类是对象的抽象,定义属性和行为;对象是类的实例。封装隐藏内部细节,只暴露必要接口。继承允许类复用和扩展属性与行为,而多态使不同类的对象能通过相同接口调用方法。C#通过访问修饰符实现封装,使用虚方法和抽象方法实现多态。理解并应用这些概念,能提升代码的清晰度和可扩展性,助你成为更好的C#程序员。
|
2月前
|
开发框架 安全 .NET
C#编程高手的成长之路
【4月更文挑战第21天】本文揭示了成为C#编程高手的路径:牢固掌握基础知识和面向对象编程,深入了解C#特性如泛型和委托,精通ASP.NET等框架工具,养成良好编程习惯,持续学习实践并参与开源项目,勇于挑战创新。通过这些步骤,不断提升编程技能,迈向C#编程的巅峰。