C#modbus通讯

nebuung 2020-10-19 10:31:43
将信捷PLC中的数据存入MySQL(RTU&TCP)
Q:巴妖妖武妻妻久灵灵
...全文
7599 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
Antony_WU_SZ 2020-10-30
  • 打赏
  • 举报
回复
引用 3 楼 nebuung 的回复:
[quote=引用 2 楼 jameswjw 的回复:]信捷PLC有数据接口吗?能取出数据吗?如果能,哪不是就对数据库的新增操作吗?
有,而且我也取出来了存到了数据库,但是数据有缺失。知识有限无奈只能找人帮忙写一个。 链接是我写的 https://download.csdn.net/download/nebuung/12928267[/quote] 你这个下载还收积分???
ziqi0716 2020-10-26
  • 打赏
  • 举报
回复
引用 12 楼 nebuung 的回复:
[quote=引用 11 楼 阿达King 的回复:]把PLC的串口线接到PC,然后用.net写程序,调用NModbus,里面有例程,直接用窗口的Timer组件不停地扫描从PLC串口传过来的数据
我面临的是这个问题: 数据丢失的原因在于数据接收与数据处理同在一个线程中,如果数据处理时间较长,来不及接收的数据只能暂存于缓存中。一旦缓存满了,新到的数据就会冲刷掉未来的及接收的数据,从而造成数据的丢失。 查到的解决方法: 数据接收与数据处理分别在两个线程中进行,数据接收线程负责数据接收并将接收的数据存入数据池中;数据处理线程负责从数据池中读取数据和处理数据。 问题是我不知道怎么改。[/quote] 真的,你还是看NModbus等现成库吧,即使你把所有问题都解决了,也只不过是写了一个类似NModbus库的轮子,而且很可能是菱形或者三角形的(学习原理及实现技巧啥的虽然也有必要的,但是从面相对象的角度来讲,你当下应该关心的是业务数据的处理,而不是如何保证数据传输的过程的安全可靠等问题).
jameswjw 2020-10-26
  • 打赏
  • 举报
回复
我大致看了一下你的代码,我可以给你一个思路,你把信捷PLC中的数据先存放到一个.txt文本文件中,首先得对比一下日志数据与数据库中的数据丢了多少?是不是循环写错了,先对比数据,我感觉不应该丢失,理论上是代码有漏洞,把哪些数据给丢了
  • 打赏
  • 举报
回复
固然,后续数据处理本来就可以跟数据 I/O 线程分开来,异步并发执行。但是异步并发时就又有新的技术、新的问题(新的bug)需要注意处理。那么前提是,最低级地开发的时候,为什么用一些技术的属于把主管直接打发掉了?为什么没有给出具体的调试结果数据,而仅仅是一个定性的说词儿?如果不会5%的技术来保证先逻辑正确地处理,你让这样的人去运用15%层级的技术,这不现实。
  • 打赏
  • 举报
回复
引用 12 楼 nebuung 的回复:
我面临的是这个问题:
数据丢失的原因在于数据接收与数据处理同在一个线程中,如果数据处理时间较长,来不及接收的数据只能暂存于缓存中。一旦缓存满了,新到的数据就会冲刷掉未来的及接收的数据,从而造成数据的丢失。。

你确定你看到“缓存满了”的代码和调试过它吗?是底下的人给你的解释吧?有些话听上去“完全正确”,但是其实根本不能当作“声东击西”的借口,而是应该找准解决方向。
nebuung 2020-10-22
  • 打赏
  • 举报
回复
引用 11 楼 阿达King 的回复:
把PLC的串口线接到PC,然后用.net写程序,调用NModbus,里面有例程,直接用窗口的Timer组件不停地扫描从PLC串口传过来的数据

我面临的是这个问题:
数据丢失的原因在于数据接收与数据处理同在一个线程中,如果数据处理时间较长,来不及接收的数据只能暂存于缓存中。一旦缓存满了,新到的数据就会冲刷掉未来的及接收的数据,从而造成数据的丢失。
查到的解决方法:
数据接收与数据处理分别在两个线程中进行,数据接收线程负责数据接收并将接收的数据存入数据池中;数据处理线程负责从数据池中读取数据和处理数据。
问题是我不知道怎么改。
阿达King哥 2020-10-22
  • 打赏
  • 举报
回复
引用 12 楼 nebuung 的回复:
[quote=引用 11 楼 阿达King 的回复:]把PLC的串口线接到PC,然后用.net写程序,调用NModbus,里面有例程,直接用窗口的Timer组件不停地扫描从PLC串口传过来的数据
我面临的是这个问题: 数据丢失的原因在于数据接收与数据处理同在一个线程中,如果数据处理时间较长,来不及接收的数据只能暂存于缓存中。一旦缓存满了,新到的数据就会冲刷掉未来的及接收的数据,从而造成数据的丢失。 查到的解决方法: 数据接收与数据处理分别在两个线程中进行,数据接收线程负责数据接收并将接收的数据存入数据池中;数据处理线程负责从数据池中读取数据和处理数据。 问题是我不知道怎么改。[/quote] 我的经验是PLC传过来的速度是非常慢的,计算机的速度是非常快的,你如果需要保存数据,可以把保存数据的操作放在另一个线程中
蜗牛慢慢趴 2020-10-21
  • 打赏
  • 举报
回复
NModbus
owennol 2020-10-21
  • 打赏
  • 举报
回复
modbus只是一种协议格式,通信还是串口或者网络,参考SerialPort和Socket
阿达King哥 2020-10-21
  • 打赏
  • 举报
回复
把PLC的串口线接到PC,然后用.net写程序,调用NModbus,里面有例程,直接用窗口的Timer组件不停地扫描从PLC串口传过来的数据
Antony_WU_SZ 2020-10-20
  • 打赏
  • 举报
回复
在西门子,三菱和台达的PLC上均可实现,经过批量生产验证.
Antony_WU_SZ 2020-10-20
  • 打赏
  • 举报
回复
libmodbus库 小菜一碟 几年前的老技术了 https://blog.csdn.net/ericwuhk/article/details/79992080
nebuung 2020-10-19
  • 打赏
  • 举报
回复
我是不知道怎么改自己的代码,求大神帮忙写个可用的,Q在一楼,马尼好说
nebuung 2020-10-19
  • 打赏
  • 举报
回复
引用 2 楼 jameswjw 的回复:
信捷PLC有数据接口吗?能取出数据吗?如果能,哪不是就对数据库的新增操作吗?

看到设置的免费下载还收C币,代码全部贴了
using System;
using System.Windows.Forms;
using Modbus.Device;
using System.IO.Ports;
using MySql.Data.MySqlClient;

namespace Modbus72
{
public partial class MainForm : Form
{
private static IModbusMaster master;
private static SerialPort port;
//写线圈或写寄存器数组
private bool[] coilsBuffer;
private ushort[] registerBuffer;
//参数(分别为站号,起始地址,长度)
private byte slaveAddress;
private ushort startAddress;
private ushort startAddress1;
private ushort numberOfPoints;
private ushort numberOfPoints1;
//串口参数 串口名 波特率 校验 数据位 停止位
private string portName;
private int baudRate;
private Parity parity;
private int dataBits;
private StopBits stopBits;
public MainForm()
{
InitializeComponent();
}

private void MainForm_Load(object sender, EventArgs e)
{
timer1.Interval = 3000;
btnstart.Enabled = true;
btnstop.Enabled = false;
}
private SerialPort InitSerialPortParameter()
{
if (cbxcom.SelectedIndex < 0)
{
MessageBox.Show("请选择串口号");
return null;
}
else
{
portName = cbxcom.SelectedItem.ToString();
baudRate = 19200;
parity = Parity.Even;
dataBits = 8;
stopBits = StopBits.One;
port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
return port;
}
}

private void btnread_Click(object sender, EventArgs e)
{
try
{
//初始化串口参数
InitSerialPortParameter();
master = ModbusSerialMaster.CreateRtu(port);
ExecuteFunction();
}
catch (Exception)
{
MessageBox.Show("初始化异常");
}
}
private void ExecuteFunction()
{
slaveAddress = byte.Parse("1");
string today = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
String connetStr = "server=10.10.20.5;port=3309;user=root;password=rootqsr; database=db_qualitymanager;";
MySqlConnection conn = new MySqlConnection(connetStr);
try
{
//每次操作是要开启串口 操作完成后需要关闭串口
//目的是为了slave更换连接是不报错
if (port.IsOpen == false)
{
port.Open();
}
startAddress = ushort.Parse("0");
numberOfPoints = ushort.Parse("20");
//读取线圈
coilsBuffer = master.ReadCoils(slaveAddress, startAddress, numberOfPoints);
for (int i = 0; i < coilsBuffer.Length; i++)
{
bool m = coilsBuffer[i];//线圈状态
if (m == true)
{
//读取寄存器
int j = i * 4 + 6;
startAddress1 = ushort.Parse(j + "");
numberOfPoints1 = ushort.Parse("3");
registerBuffer = master.ReadHoldingRegisters(slaveAddress, startAddress1, numberOfPoints1);
string x = registerBuffer[0] + "";
string y = registerBuffer[2] + "";
if (x == "0")
{
continue;
}
else
{
if (i < 10)
{
#region
string dpr = "z_0" + i;
conn.Open();
string sql = string.Format("insert into " + dpr + "(vultime,opetime,prdate) values ('{0}','{1}','{2}')", x, y, today);
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.ExecuteNonQuery();
conn.Close();

//修改寄存器
string s = j + "";
startAddress = ushort.Parse(s);
string[] strarr = { "0" };
registerBuffer[0] = ushort.Parse(strarr[0]);
master.WriteSingleRegisterAsync(slaveAddress, startAddress, registerBuffer[0]);
#endregion
}
else
{
#region
string dpr = "z_" + i;
conn.Open();
string sql = string.Format("insert into " + dpr + " (vultime,opetime,prdate) values ('{0}','{1}','{2}')", x, y, today);
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.ExecuteNonQuery();
conn.Close();

//修改寄存器
string s = j + "";
startAddress = ushort.Parse(s);
string[] strarr = { "0" };
registerBuffer[0] = ushort.Parse(strarr[0]);
master.WriteSingleRegisterAsync(slaveAddress, startAddress, registerBuffer[0]);
#endregion
}
}
}
//SetMsg(coilsBuffer[i] + " ");
}
//SetMsg("\r\n");
port.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

public void SetMsg(string msg)
{
showdetail.Invoke(new Action(() => { showdetail.AppendText(msg); }));
}

private void btnclear_Click(object sender, EventArgs e)
{
showdetail.Clear();
}

private void btnstart_Click(object sender, EventArgs e)
{
timer1.Start();
btnstart.Enabled = false;
btnstop.Enabled = true;
}

private void btnstop_Click(object sender, EventArgs e)
{
timer1.Stop();
btnstart.Enabled = true;
btnstop.Enabled = false;
}

private void timer1_Tick(object sender, EventArgs e)
{
btnread.PerformClick();
}
}
}
nebuung 2020-10-19
  • 打赏
  • 举报
回复
引用 2 楼 jameswjw 的回复:
信捷PLC有数据接口吗?能取出数据吗?如果能,哪不是就对数据库的新增操作吗?

有,而且我也取出来了存到了数据库,但是数据有缺失。知识有限无奈只能找人帮忙写一个。
链接是我写的 https://download.csdn.net/download/nebuung/12928267
jameswjw 2020-10-19
  • 打赏
  • 举报
回复
信捷PLC有数据接口吗?能取出数据吗?如果能,哪不是就对数据库的新增操作吗?
nebuung 2020-10-19
  • 打赏
  • 举报
回复
没人接的么,不费时间的项目啊
ziqi0716 2020-10-19
  • 打赏
  • 举报
回复
可以看看NModBus这个库.
源码链接: https://pan.quark.cn/s/0f7c75cb3aad ### MIPI Video Mode 与 Command Mode 的差异 #### 一、引言 MIPI (Mobile Industry Processor Interface) 是一种用于连接移动设备中处理器及其外围设备的标准化接口。MIPI 接口支持多种协议,其中包含 DSI (Display Serial Interface) 和 DCS (Display Control Interface) 等协议。在 MIPI 接口的应用中,主要涉及两种工作模式:Video Mode(视频模式)和 Command Mode(命令模式)。本文旨在系统性地阐述这两种模式的工作机制、特性以及实际应用环境。 #### 二、LCD RAM 概念说明 在进一步探讨 MIPI 的两种模式之前,有必要对文中提及的“LCD RAM”概念进行明确。实际上,“LCD RAM”并非一个通用术语,而是本文作者用来描述 LCD 控制器中用于存储显示数据的内存区域。LCD(Liquid Crystal Display,液晶显示屏)通常配备一个控制 IC(Integrated Circuit,集成电路),该控制 IC 可能内置 RAM 以缓存显示数据。 #### 三、MIPI Video Mode(视频模式) **定义:** - 视频模式是一种类似于传统 RGB 接口的工作模式,它要求主机持续不断地向显示器传输刷新数据。 - 在这种模式下,数据和控制信号以报文的形式通过 MIPI 总线进行传输。 - 显示器本身无需配备帧缓冲器,因为主机会周期性地刷新屏幕。 **特点:** 1. **实时性高:** 主机需要不...
源码下载地址: https://pan.quark.cn/s/a4b39357ea24 在电磁模拟技术中,CST(Computer Simulation Technology)是一种被广泛采纳的软件工具,它主要用于电磁场、微波、天线以及射频系统的设计工作。本资料将详细分析CST软件中离散端口的具体配置方法,这些方法对于提升仿真结果的精确度和专业水准具有决定性作用。离散端口在CST软件中扮演着模拟信号输入或输出的重要角色,它们构成了仿真模型不可或缺的部分。在配置离散端口时,一个核心的原则是保证端口的方向与网格线保持一致,这是因为这样做能够有效降低计算过程中产生的误差,并确保仿真数据的有效性。如果未能遵循这一指导原则,可能会引发未知的计算问题,进而导致仿真结果失去可靠性。 在CST软件中配置离散端口,通常需要借助“Pick Points”这一功能。通过选择“Pick Edge Center”选项,端口将被设定在模型边缘的中心位置上。然而,这种做法并不总是能够确保端口与网格线保持平行。在某些特定情形下,模型的几何构造可能不允许直接选取一个与网格线平行的边作为端口的安装位置。 为了克服这一挑战,可以采用多种不同的策略。如果模型本身已经包含一条与馈电口平行的边,那么可以直接利用这条边来建立端口,此时CST软件会自动调整端口使其与网格线对齐。另一种可选的方法是,当模型不具备现成的平行边时,用户可以手动构建一个几何结构,比如一个立方体,并使其边缘与馈电口平行。通过这种方式,新建立的几何结构的边缘就可以作为端口的位置,从而确保端口与网格线的平行关系。 在实施上述操作时,必须关注端口尺寸的合理性和物理意义的一致性。端口的尺寸应当依据实际天线馈电部分的尺寸进行适当调整,过大的端口或...
代码下载链接: https://pan.quark.cn/s/a4b39357ea24 【使用TensorFlow进行图像识别】 图像识别作为计算机视觉领域的关键任务之一,其核心在于通过算法解析和理解图像所包含的信息。在此资源中,我们将集中探讨如何借助功能强大的深度学习框架TensorFlow来执行手写数字识别。手写数字识别构成了众多实际应用的基础,例如自动支票处理、光学字符识别(OCR)等场景。 TensorFlow是由Google创建的一个开源库,它主要用于数值运算和机器学习,尤其在深度学习方面表现卓越。其核心优势在于可以构建并训练复杂的神经网络架构,并且在多种硬件环境中实现高效执行,涵盖CPU和GPU平台。 在此实践项目中,我们将运用TensorFlow来构建一个卷积神经网络(CNN)模型,这种架构是处理图像数据的理想选择。CNNs通过模仿人脑视觉皮层的运作机制,能够自主地提取图像中的关键特征,进而达成识别目标。在手写数字识别的特定情境下,这些特征可能涉及笔画的几何形态、走向以及相互间的连接模式。 对于CNN的基础结构,我们需要具备相应的认知,其通常由卷积层、池化层、全连接层以及激活函数等部分组成。卷积层借助滤波器(亦称卷积核)对图像进行扫描,以捕捉局部特征;池化层则用于降低数据维度,同时保留核心信息;全连接层将特征向量映射至各类别的概率分布;而激活函数如ReLU则通过引入非线性元素,使模型能够学习更为复杂的模式。 在此案例中,建议采用MNIST数据集,这是一个广泛用于手写数字识别的标准测试集。该数据集包含60,000个训练样本和10,000个测试样本,每个样本均为28x28像素的灰度图像,代表0到9这十个数字中的某一个。为了训练模型,必须首先加载数据,并...

111,129

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧