2024年1月24日发(作者:)
C# 读写西门子 PLC数据并实现语音报警
1. 西门子 PLC配置及程序
2. Wincc和西门子通讯配置
3. C# OPC读取PLC数据(通过WINCC)
4. C# 文字转语音
5. 完整程序
先演示一下效果:
选择Wincc做OPCserver
4个变量值显示
点击“写数据”,会把上面textbox的3写入变量1和变量2,程序中设定的只能写这2个
1
1. 西门子 PLC配置及程序
1.1 硬件配置
新建一个工程,插入一个带以太网的CPU(和WINCC通过以太网连接),如下:
IP地址设置
1.2 软件设计
简易程序实现加减乘除累计
CPU设置M0.5每
1S触发一次
以上做完后,我们下载到S7-PLCSIM就可以开始仿真了。
2
2. Wincc和西门子通讯配置
新建一个Wincc工程,打开变量管理:
3. C# 文字转语音
引用自带的
选择“添加新的驱动程序”->S7 Protocol Suite,然后新建一个TCP/IP 连接:
添加变量:
此处我们仅仅是测试C#读取PLC数据,Wincc只是用作OPC服务器,因此只需要配置到这边就结束了,其它画面编辑什么的这里不做介绍。
3
3. C# OPC读取PLC数据(通过WINCC)
OPC的数据访问方法分别有同步访问、异步访问和订阅式数据采集方式三种。之前在ABB
PLC和C#通讯介绍了订阅式数据采集,此处再介绍一下异步读取数据,写入数据还是通过异步方法。
//OPC异步读取数据
private void Group_AsyncReadComplete(int TransactionID, int NumItems, ref Array
ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps, ref Array
Errors)
{
for (int i = 1; i < NumItems+1; i++)
{
d[32(ue(i))] =
le(ue(i));
}
= d[1].ToString();
= d[2].ToString();
= d[3].ToString();
= d[4].ToString();
}
此处需要注意,ClientHandles当我每次重新换变量读取数据是,不是1~4这个顺序—_—,避免界面显示的变量值对于不上(如果直接D[i]= le(ue(i)); 变量和值就对于不上了…)因此按照客户端句柄来读取。
//OPC异步写入数据
private void WBtn_Click(object sender, RoutedEventArgs e)
{
Array AsycWr_Value;
Array SerHandles;
object[] tempWrData = new object[3];//写入的数据必须是object类型的
int[] tempSerHandles = new int[3];
//将输入的数据赋给数组,然后转成Array给AsycWr_Value
tempWrData[1] = (object);
tempWrData[2] = (object);
AsycWr_Value = (Array)tempWrData;
//将输入数据对应的服务器句柄赋给变量,然后转成Array类型给SerHandles
tempSerHandles[1] = 32(ue(1));
tempSerHandles[2] = 32(ue(2));
SerHandles = (Array)tempSerHandles;
try
{
rite(2, ref SerHandles, ref AsycWr_Value, out Errors_Wr, TransactionID, out
CancleID);
}
catch (Exception e1)
4
{
ShowMessage(ng());
}
4. C# 文字转语音
引用自带的
//三个参数:语速,音量,内容
public void SpeechVideo_Read(int rate, int volume, string speektext)
{
= rate;
= volume;
sync(speektext);
}
if (Value1>80) //语音报警测试
{
SpeechVideo_Read(0, 80, "当前液位为" + ng() + "液位高报警");
}
5
5. 完整程序
using System;
using s;
using ;
using sis;
using OPCAutomation;
using ;
using ing;
namespace ABB语音报警
{
public partial class MainWindow : Window
{
OPCServer Server;
OPCGroups Groups;
OPCGroup Group;
OPCItems Items;
private bool Flag = true;
double[] d = new double[100];
SpeechSynthesizer speech = new SpeechSynthesizer();
Array strItemIDs;
Array cHandles;
Array sHandles;
Array Erros_read;
Array Errors_Wr;
int TransactionID = 1;
int CancleID;
bool Read_Flag;
object RequestDataTypes = null;
object AccessPaths = null;
public MainWindow()
{
InitializeComponent();
Server = new OPCServer();
}
6
private void Btn2_click(object sender, RoutedEventArgs e)//获取OPC服务器
{
if ( == " ")
{
("请先输入IP地址!");
}
else
{
string ip = ();//去除两端空格
try
{
//过去计算机名Win7貌似新的不行,Win10可以,因此此处还是采用老的方法
object progIds = Servers(tByAddress(ip).HostName);
foreach (var item in (Array)progIds)
{
(item);//所有OPC服务器放入Combox中
}
edIndex = 0;//默认选择第一个OPC服务器
if ( == null)
{
ShowMessage("获取服务器失败,请检查OPC服务器是否启动!");
}
else
{
ShowMessage("成功获取OPC服务器!");
}
}
catch (Exception err)
{
ShowMessage(ng());
}
}
}
private void ShowMessage(string str)//文本框消息提示
{
Text(str + "rn");
ToEnd();
}
7
private void Btn3_Click(object sender, RoutedEventArgs e)//连接OPC服务器
{
if ( == "")
{
("请先选择OPC服务器!");
}
else
{
try
{
if (State == 32(connected))
{
t();
t = "断开OPC服务器";
ShowMessage("成功连接OPC服务器!");
Groups = ups;
tGroupDeadband = 0;//缓冲区死区
tGroupIsActive = true;//缓冲区活动激活
tGroupUpdateRate = 1000;//缓冲区刷新时间
Group = ("group1");
cribed = true; //缓冲区订阅Datachange事件
Items = ms;
riteComplete += Group_AsyncWriteComplete;//异步写入数据事件
eadComplete += Group_AsyncReadComplete;//异步读取数据事件
string[] tmpIDs = new string[5];
int[] tmpCHandle = new int[5];
for (int i = 1; i < 5; i++)
{
tmpCHandle[i] = i;
}
tmpIDs[1] = ;
tmpIDs[2] = ;
tmpIDs[3] = ;
tmpIDs[4] = ;
strItemIDs = (Array)tmpIDs;
cHandles = (Array)tmpCHandle;
ms(4, ref strItemIDs, ref cHandles, out sHandles, out Erros_read,
RequestDataTypes, AccessPaths);
}
8
else
{
nect();
t = "连接OPC服务器"; ;
ShowMessage("OPC服务器连接已断开!");
}
}
catch (Exception err)
{
ShowMessage(ng());
}
}
}
private void Btn4_click(object sender, RoutedEventArgs e)//开始/停止 读取数据{
if (Flag == true)
{
Thread th1 = new Thread(Asyc_Read) //新建读取数据线程
{
IsBackground = true
};
();
t = "停止读取数据";
ound = ;
Flag = false;
Read_Flag = true;
}
else
{
t = "开始读取数据";
ound = new SolidColorBrush(b(221,221,221));
Flag = true;
Read_Flag = false;
}
}
9
private void Asyc_Read()//异步读取数据,间隔1秒
{
while (Read_Flag)
{
ead(4, ref sHandles, out Erros_read, TransactionID, out CancleID);
(1000);
}
}
//异步读取数据完成,数据处理
private void Group_AsyncReadComplete(int TransactionID, int NumItems, ref Array
ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps, ref Array
Errors)
{
for (int i = 1; i < NumItems+1; i++)
{
d[32(ue(i))] =
le(ue(i));
}
= d[1].ToString();
= d[2].ToString();
= d[3].ToString();
= d[4].ToString();
if (d[1] > 80)
{
ShowMessage("当前液位为" + d[1].ToString() + "液位高报警");
SpeechVideo_Read(0, 80, "当前液位为" + d[1].ToString() + "液位高报警");
}
if (d[2] < 10)
{
ShowMessage("当前液位为" + d[2].ToString() + "液位低报警");
SpeechVideo_Read(0, 80, "当前液位为" + d[2].ToString() + "液位低报警");
}
}
// rate:范围为:-10~10; volume:范围为:0~100; speektext:待转换声音的文字
public void SpeechVideo_Read(int rate, int volume, string speektext) // 语速,音量,内容
{
10
= rate;
= volume;
sync(speektext);
}
private void WBtn_Click(object sender, RoutedEventArgs e)//OPC异步写数据
{
Array AsycWr_Value;
Array SerHandles;
object[] tempWrData = new object[3];//写入的数据必须是object类型的
int[] tempSerHandles = new int[3];
//将输入的数据赋给数组,然后在转成Array给AsycWr_Value、
tempWrData[1] = (object);
tempWrData[2] = (object);
AsycWr_Value = (Array)tempWrData;
//将输入数据的Item对于服务器句柄赋给数据,然后转成Array类型给SerHandles
tempSerHandles[1] = 32(ue(1));
tempSerHandles[2] = 32(ue(2));
SerHandles = (Array)tempSerHandles;
try
{
rite(2, ref SerHandles, ref AsycWr_Value, out Errors_Wr, TransactionID, out
CancleID);
}
catch (Exception e1)
{
ShowMessage(ng());
}
}
private void Group_AsyncWriteComplete(int TransactionID, int NumItems, ref Array
ClientHandles, ref Array Errors)
{
ShowMessage(ng() + "个数据写入成功!");
}
}
}
11


发布评论