C# SerialPort 读写三菱FX系列PLC

2023-05-16

1:串口初始化  

com = new SerialPort("COM3", 9600, Parity.Even, 7, StopBits.One);

2:打开关闭串口

if (com.IsOpen)

 {com.Close();}

com.Open();

 

if (com.IsOpen)

{ com.Close();}

3:C# ASCII转字符及字符转ASCII

public static string Chr(int asciiCode)
        {
            if (asciiCode >= 0 && asciiCode <= 255)
            {
                System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();
                byte[] byteArray = new byte[] { (byte)asciiCode };
                string strCharacter = asciiEncoding.GetString(byteArray);
                return (strCharacter);
            }
            else
            {
                throw new Exception("ASCII Code is not valid.");
            }

        }

 

public static int Asc(string character)
        {
            if (character.Length == 1)
            {
                System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();
                int intAsciiCode = (int)asciiEncoding.GetBytes(character)[0];
                return (intAsciiCode);
            }
            else
            {
                throw new Exception("Character is not valid.");
            }

        }

 

4:写入串口的命令字符串的和校验

 

/// <summary>
        /// 和校验
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public string SumCheck(string data)
        {
            int sum = 0;
            for (int i = 0; i < data.Length; i++)
            {
                sum += Asc(data.Substring(i, 1));
            }

            string res = sum.ToString("X");
            res = res.Substring(res.Length - 2, 2);

            return res;

        }

 

 5:写入PLC

private void btnWrite_Click(object sender, EventArgs e)

        { 

            string[] write = new string[] { "2","2"}; //将准备写入PLC的值
            //将要写入的值转换成16进制数,补齐两个字节,注意高低字节需要交换
            string sWriteData = "";
            for (int i = 0; i < write.Length; i++)
            {
                int val = Convert.ToInt32(write[i].Length>0?write[i]:"0");
                string s = val.ToString("X");
                while (s.Length<4)
                {
                    s = "0" + s;
                }
                sWriteData += s.Substring(2,2)+s.Substring(0,2);
            }

            MessageBox.Show(sWriteData);
            //写入命令,1表示写入,1194表示D202这个地址的16进制,04表示D202,D203为4个BYTE,1194=(202*2)+4096的16进制数,至于用它表示D202的起始位置,三菱故意要这么麻烦了.
            sWriteData = "1119404" + sWriteData + Chr(3);
            //chr(2)和chr(3)是构成命令的标志字符,然后加上校验和,命令组织完成
            sWriteData = Chr(2) + sWriteData + SumCheck(sWriteData);

            MessageBox.Show(sWriteData);
            //写入串口
            com.Write(sWriteData);
            //byte[] data = Encoding.ASCII.GetBytes(sWriteData); 
            //com.Write(data,0,data.Length);

        }

 

6:读PLC

 private void btnRead_Click(object sender, EventArgs e)
        {
            
            this.txtRead0.Clear();
            string sReadData = "";

            //在读PLC中的数据之前,需要先发个指令给它,让它将数据发送到串口,下面的字符串中,chr(2),chr(3)为PLC命令的格式标志,0119404中,0表示读,1194表示D202的起始地址,04表示读D202,D203两个字,共4个字节,66为0119404和chr(3)的校验和,向串口写入"读"命令,其实和向plc地址中写入数据是一样的,只是没有数据,用0表示读

            string sReadCmd = Chr(2) + "0119404" + Chr(3) + "66";
            com.Write(sReadCmd);
            //等待1秒钟
            System.Threading.Thread.Sleep(1000);
            // 从串口读数据
            byte[] data = new byte[1024];
            com.Read(data, 0, 1024);

           //如果首位为2,则表示数据有效.这里有个问题,在第二次读,第2位才为'2',第三次又是首位为2,需要再测试
            if (data[0]==2)
            {
                string sReceiveData = System.Text.Encoding.ASCII.GetString(data);
                //MessageBox.Show(sReceiveData);
               //解析命令,将读到的字符解析成数字,注意高低位的转换
                for (int i = 1; i < 8; i += 4)
                {
                    string sLow = sReceiveData.Substring(i,2);
                    string sHigh = sReceiveData.Substring(i + 2, 2);
                    //int res = Convert.ToInt32(sHigh)+ Convert.ToInt32(sLow);
                    int res = Convert.ToInt32(sHigh,16) + Convert.ToInt32(sLow,16);

                    this.txtRead0.Text += res.ToString() + ",";
                }               
                
            }



 

 

分类:  C#
好文要顶  关注我  收藏该文   
白沙河
关注 - 0
粉丝 - 3
+加关注
2
(请您对文章做出评价)
« 上一篇: 无法加载 DLL“sqlceme30.dll”: 找不到指定的模块。解决
» 下一篇: MSComm控件使用详解
posted on  2008-12-29 09:20  白沙河 阅读( 3929) 评论( 8)  编辑  收藏

FeedBack:
#1楼
2009-02-25 11:42 |  Ryan.net
博主用的哪一款PLC? 
我也在用这东西FX2N(RS232),他给的手册好像不是这样说的。。。。 
手册示例: 
在第5站从X040向X077读32个点的数据(消息等待时间设为100毫秒) 
应该向PLC发送: 
ENQ 站号 PC号 读写指令 响应时间 起始地址 读取位数 和校验码 
ENQ 0 5 F F W R 0 X 0 0 4 0 0 2 4 8 
05H 30H 35H 46H 46H 57H 52H 30H 58H 30H 30H 34H 30H 30H 32H 34H 38H 

我发送 
m_ComPort.COM.Write(ASCIIEncoding.ASCII.GetString(byteTmp) + "FFWR0X004002" + SumChk("FFWR0X004002")); 
可是获取不到正确的数据
支持(0) 反对(0)
  
#2楼 [ 楼主]
2009-02-25 12:01 |  白沙河   
Public Const PLC_X_Group_Base_AddRess = 128

X地址是不是要先加一个128?
支持(0) 反对(0)
  
#3楼
2009-02-25 14:23 |  Ryan.net
先谢谢博主回复 

不过没太看明白 

格式如下(中间用“|”人为分割): 
在第5站从X040向X077读32个点的数据(消息等待时间设为100毫秒) 
ENQ|站号|PC号|读写指令|响应时间|起始地址|读取位数|和校验码 
ENQ|0 5 |F F|W R|0 |X 0 0 4 0| 0 2| 4 8 
05H|30H 35H |46H 46H |57H 52H |30H |58H 30H 30H 34H 30H |30H 32H|34H 38H 
我写的代码: 
m_ComPort.COM.Write(Chr(5) + "FFWR0X004002" + SumChk("FFWR0X004002")); 

X地址加一个128? 
是不是X0040转换成ASC之后加128 
支持(0) 反对(0)
  
#4楼 [ 楼主]
2009-02-25 15:18 |  白沙河   
以下资料是从网上找的,没有找到关于X的字或位的说明.但SumChk("FFWR0X004002"))应该不是从0x0040开始吧
//

由于没有寄存器类型信息,所以地址的计算十分关键,如D100和M100分别对应哪个地址呢?下面就是三菱Fx系列PLC地址对应表:

Public Const PLC_D_Base_AddRess = 4096
Public Const PLC_D_Special_Base_AddRess = 3584
Public Const PLC_Y_Group_Base_AddRess = 160
Public Const PLC_PY_Group_Base_AddRess = 672
Public Const PLC_T_Group_Base_AddRess = 192
Public Const PLC_OT_Group_Base_AddRess = 704
Public Const PLC_RT_Group_Base_AddRess = 1216
Public Const PLC_M_SINGLE_Base_AddRess = 2048(命令为7或8时)
Public Const PLC_M_Group_Base_AddRess = 256
Public Const PLC_PM_Group_Base_AddRess = 768
Public Const PLC_S_Group_Base_AddRess = 0
Public Const PLC_X_Group_Base_AddRess = 128
Public Const PLC_C_Group_Base_AddRess = 448
Public Const PLC_OC_Group_Base_AddRess = 960
Public Const PLC_RC_Group_Base_AddRess = 1472
Public Const PLC_TV_Group_Base_AddRess = 2048
Public Const PLC_CV16_Group_Base_AddRess = 2560
Public Const PLC_CV32_Group_Base_AddRess = 3072 

当我们用DEVICE READ命令时,D100地址=100*2+4096;M100地址=100+256;不同的是D类型寄存器存放的是字,M寄存器存放的是位,同样是读两个字节,D100返回的就是PLC中D100地址的值,M类型寄存器返回的是M100到M116的值。所以当我们用FORCE ON 命令时,M100寄存器地址=100+2048;

这也没有什么复杂的,不是吗?可是三菱公司好像不甘于如此,FORCE ON/Off命令中地址排列与DEVICE READ/WRITE不同,是低位在前高位在后。如Y20,地址是0510H,代码中4个字节地址表示为:1005。(注意:Y寄存器为八进制,如Y20 地址=16+1280=0510H) 

其实一点技术含量都没有,就是拐了几个弯,偏偏很多时候又不都告诉你,让人浪费不少时间。
支持(0) 反对(0)
  
#5楼
2009-02-25 18:02 |  Ryan.net
谢了,兄弟! 
和厂商通过另外一种模式解决了 
因为时间实在太急,对于这些东西懂得也不多,就没能继续研究
支持(0) 反对(0)
  
#6楼
2009-06-24 10:28 |  明月伴我行   
你好,请教如何读D1024后面的值?我现在一直返回零,郁闷。
支持(0) 反对(0)
  
#7楼 [ 楼主]
2009-06-26 09:56 |  白沙河   
@明月伴我行
假设读2个地址,那是不是应该以"0180004"开始,手里没有PLC,也没有试过从1024开始,所以也就不确定了.
支持(0) 反对(0)
  
#8楼
2009-07-14 17:29 |  明月伴我行   
应该不是
支持(0) 反对(0)
  
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# SerialPort 读写三菱FX系列PLC 的相关文章

  • 是否可以知道RS232端口的连接状态?

    在 9 针电缆中 你们建议使用哪个信号 针来检查连接状态 到目前为止我正在使用DSR信号因为 在我正在测试的硬件中 如果电缆连接正确 则 DSR 信号是1如果断开连接 DSR 将转至0 然而 对于其他驱动程序和 或操作系统 DSR 在消息传
  • 从 C 读取串行数据 (OSX /dev/tty)

    我正在尝试使用 C 从蓝牙条形码扫描仪 KDC300 读取数据 这是我到目前为止的代码 并且该程序成功建立了与扫描仪的蓝牙连接 但是当扫描条形码时 上没有显示任何输入屏幕 最终将用数据完成更多工作 但我们必须首先让它工作 对吧 这是程序 i
  • 串口通讯显示

    我正在尝试通过串行端口通信进行聊天 这个聊天必须在 WPF 项目中有一个界面 我已经制作了界面和所有内容 我陷入了通过串口接收响应的困境 我已经尝试从串行端口添加 DataReceived 事件 但我担心我使用错误 因为我以前从未用 C 编
  • STM32 上的 ADC 单次转换

    我正在研究 STM32 F103x 上的 ADC 编程 并从最简单的情况 单次转换开始 测量内部温度传感器 连接到 ADC1 的值 并使用 USART 将其发送到 COM 端口 目标似乎很明确 但是当我尝试将源代码下载到闪存时 它不会向 C
  • .NET 错误关闭串口 BaseStream 错误仅在端口打开时出现

    我正在使用 NET System IO Ports SerialPort 并按照本文中的建议使用 BaseStreamIf you must使用 NET System IO Ports SerialPort http www sparxen
  • C++ Linux (Ubuntu) 正确写入串行(对于 Arduino)

    我想知道是否有一种标准方法可以与高效的串行设备进行通信 我应该使用标准库吗 如果有 是哪一个 现在我正在摆弄让 LED 根据输入的数字以给定的量亮起 Arduino 代码如下 只是练习一些东西 看我过于简单且低效的测试 include
  • 可靠的全双工串行通信

    我正在设计一种设备 它将加密从 PC 发送的长 假设无限 数据流并将其发回 我计划在运行全双工的设备上使用单个串行端口 并通过硬件握手来 阻止 数据 在每个块后发送一个 CRC 值 该设备只会缓冲有限数量的块 理想情况下 只有一个缓冲区累积
  • 以串行对象作为参数的多进程

    我在使用 Python 并将串行对象作为参数传递给单独的进程时遇到问题 该程序在 Windows 8 中运行 因此不能选择使用全局变量 from multiprocessing import Queue from multiprocessi
  • 如何通过串口连接Android模拟器与桌面?

    我有一个模拟器应用程序 可以将串行命令发送到 Android 设备 反之亦然 为了使用此应用程序 我需要通过物理 RS 232 电缆连接真正的 Android 设备 然后选择设备 我的问题是 有没有办法在模拟器和Mac Linux PC之间
  • C# - 从串口缓冲区读取

    我正在尝试从 RS 232 端口读取数据 有谁有一个例子说明我如何从端口 缓冲区获取数据并确保我拥有所有数据 因为它可以是多行数据 我只是简单地读如下吗 string Rxstring port ReadLine Console Write
  • 使用 /dev/tty* 进行 9 位 uart 仿真

    我有一个不常见的协议 它需要 9600 波特率 9 位和 1 个停止位 我找不到任何可以实现此发送 接收的驱动程序 我可以寄东西到 dev tty 用于模拟这些查询 我应该发送什么 如何模拟 9600 波特率 您可以使用粘性奇偶校验 也称为
  • Linux 上共享串口

    我正在使用 Raspberry Pi 进行一个项目 该项目需要能够写入和读取串行端口 但来自不同的程序 程序 A 需要能够从外围设备 A 正在发送数据的串行端口读取数据 程序B需要向串口写入数据 外设B正在监听串口 供参考 本例中程序A是G
  • 二进制串口读取c中丢失的字节

    我正在将二进制数据从 arduino 发送到运行此代码的串行端口 在十六进制模式下使用cutecom可以清楚地读取我对该串行端口的期望 如下所示 00000000 24 04 85 ab 47 43 04 04 24 04 85 ab 47
  • .NET 有成功的 profibus 通信吗?

    有没有人聊成功了profibus http www profibus com 来自 NET 应用程序 如果您这样做了 您使用什么设备 卡来完成此操作 应用程序是什么 以及您是否使用任何类型的预先存在或可用的代码 我们没有使用过Profibu
  • Node.js |如何通过串口向设备发送和接收一个字节?

    我正在尝试编写使用以下方法的 Node js 脚本serialport https serialport io 用于读取和写入数据的 npm 包COM5串行端口 使用 RS 232 电缆连接到设备 该设备会自动传输其拥有的数据 要检索设备内
  • 如何将大于127的ASCII值发送到串口

    每当我将任何大于 127 的 ASCII 值发送到 com 端口时 我都会在串行端口上收到垃圾输出值 ComPort Write data 严格来讲ASCII http en wikipedia org wiki ASCII仅包含 128
  • TwinCAT 3:写入文件

    我想从 PLC 中导出一些数据 方法是将其写入文本文件并将其保存到 USB 记忆棒中 我设法创建了文本文件 但我无法写入任何内容 我在以下代码中使用 TwinCAT 标准库中的函数 PROGRAM P WriteFile VAR nStat
  • Python串口通信

    我正在开发一个 Arduino 项目 由于内存限制 我将其与 Python 脚本连接起来 在Python方面 我有一个二维矩阵 其中包含各自的x y坐标值 并且在此列表中有26000个坐标对 因此 为了向大家澄清数据结构 pathlist
  • Windows平台下C语言控制串口DTR和RTS引脚

    如何在windows平台上控制串口的DTR和RTS引脚 我希望通过升高或降低电压来对其进行位敲击或操作 您需要使用EscapeComm 函数 https learn microsoft com en us windows desktop a
  • 使用 python 进行串行数据记录

    Intro 我需要编写一个小程序来实时读取串行数据并将其写入文本文件 我在读取数据方面取得了一些进展 但尚未成功地将这些信息存储在新文件中 这是我的代码 from future import print function import se

随机推荐

  • centos多个vnc不同账户同时登录

    装备工作 1 更新yum源 xff0c 一开始我没有更新 xff0c 但是在第二步会出错 yum update 2 安装图形界面服务 yum groupinstall GNOME Desktop 3 安装vpc服务 yum y instal
  • C# 调用C++ DLL 的类型转换对应列表

    C 调用C 43 43 的DLL搜集整理的所有数据类型转换方式 可能会有重复或者多种方案 自己多测试 c 43 43 HANDLE void c System IntPtr c 43 43 Byte unsigned char c Syst
  • 编写程序重复定义Bug(multiple definition of)解析

    如果两个函数 方法重复定义就会报 multiple definition of 错误 xff1b 如果非要定义两个函数同名 xff0c 则可以在函数前加static xff0c 便可以将两个同名函数编译过 1 给每一个头文件加条件编译 在编
  • qt中QString与char *类型相互转换

    在进行编程时 xff0c 我们经常需要用到字符串这种类型 xff0c 毫无疑问 xff0c Qt 库中也对字符串类型进行了封装 xff0c QString 类提供了你能想到的所有字符串操作方法 xff0c 给开发者带来了极大方便 但是我们在
  • 总结以下三种方法,实现c#每隔一段时间执行代码:

    总结以下三种方法 xff0c 实现c 每隔一段时间执行代码 xff1a 方法一 xff1a 调用线程执行方法 xff0c 在方法中实现死循环 xff0c 每个循环Sleep设定时间 xff1b 方法二 xff1a 使用System Time
  • struct的创建

    本文实例分析了C 中结构 struct 的部分初始化和完全初始化 xff0c 分享给大家供大家参考 具体分析如下 xff1a 假设有这样一个值类型struct xff0c 如下所示 xff1a 1 2 3 4 5 6 7 8
  • c++全局变量的正确声明

    C 43 43 中全局变量声明错误情况 造成 LNK2005 错误主要有以下几种情况 xff1a 1 xff0e 重复定义全局变量 可能存在两种情况 xff1a A 对于一些初学编程的程序员 xff0c 有时候会以为需要使用全局变量的地方就
  • C++函数声明和定义

    在上一节 xff0c 我们已经学会了如何阅读函数原型和如何调用一个函数 然而 xff0c 仅靠系统给出的标准库函数是不够用的 我们有时候要根据我们的实际要求 xff0c 写出一个合适自己使用的函数 那么 xff0c 我们如何来自己动手编写一
  • cpp之间函数引用和类引用的方法

    除了 include外 xff0c cpp文件之间怎么引用函数 file C h ifndef FOO H define FOO H extern void sayHello endif FOO H file B cpp include 3
  • 在C++中调用DLL中的函数

    1 dll 的优点 代码复用是提高软件开发效率的重要途径 一般而言 xff0c 只要某部分代码具有通用性 xff0c 就可将它构造成相对独立的功能模块并在之后的项目中重复使用 比较常见的例子是各种应用程序框架 xff0c ATL MFC 等
  • HC-SR04超级简单教程(快速入门)

    目录 一 模块介绍 xff08 个人理解 xff09 1 简单理解 2 该模块的参数 二 HC SR04的操作 三 代码 1 代码前的注意事项 2 关键代码 四 代码实战效果图 五 结束 一 模块介绍 xff08 个人理解 xff09 1
  • C++中对于类来说头文件(.h)和源文件(.cpp)都应该写些什么 (类的常规创建)

    头文件 h xff1a 写类的声明 xff08 包括类里面的成员和方法的声明 xff09 函数原型 define常数等 xff0c 但一般来说不写出具体的实现 在写头文件时需要注意 xff0c 在开头和结尾处必须按照如下样式加上预编译语句
  • c#的接口详解

    什么是接口 xff1f 其实 xff0c 接口简单理解就是一种约定 xff0c 使得实现接口的类或结构在形式上保持一致 个人觉得 xff0c 使用接口可以使程序更加清晰和条理化 xff0c 这就是接口的好处 xff0c 但并不是所有的编程语
  • C语言中的全局变量定义与使用

    1 书中对 全局变量 的定义 在函数内定义的变量是局部变量 xff0c 而在函数外定义的变量叫做外部变量 xff0c 外部变量是全局变量 全局变量可以为本文件中其他函数所共用它的有效范围从定义变量的位置开始到本源文件结束 建立全局变量的作用
  • C,C++,C#note

    1 c 43 43 中的类的定义和声明可以都写在头文件中 xff0c 然后cpp文件include头文件 xff1b 也可以声明在头文件 xff0c 定义在cpp文件 xff1b 或者所有声明和定义都放在cpp文件 xff1b 混写定义与声
  • 在C++中可以用3种方法访问一个字符串

    用字符数组存放一个字符串 例6 10 定义一个字符数组并初始化 xff0c 然后输出其中的字符串 ol class snippet num style margin top 0px margin bottom 0px margin left
  • 动态存储和静态存储区域区别

    动态存储方式 所谓动态存储方式是指在程序运行期间根据需要进行动态的分配存储空间的方式 动态存储变量是在程序执行过程中 xff0c 使用它时才分配存储单元 xff0c 使用完毕立即释放 典型的例子是函数的形式参数 xff0c 在函数定义时并不
  • c++中默认32位int类型转换截取高位部分

    int类型的变量固定为4个字节 xff0c 共32位 int类型变量初始值一般为0 xff0c 范围 2 31 2 31 1 即 2147483648 xff0c 2147483647 16 位系统下 xff0c int 是 2 个字节 x
  • c#-接口

    c 中的接口中必须是未实现的方法 xff0c 例如属性 xff0c 事件 xff0c 索引器 xff0c 一般函数等 除此之外不能有其他的成员 xff0c 类可以继承两个或两个以上的接口 xff0c 派生类中必须实现接口中的所有方法
  • C# SerialPort 读写三菱FX系列PLC

    1 xff1a 串口初始化 com 61 new SerialPort 34 COM3 34 9600 Parity Even 7 StopBits One 2 xff1a 打开关闭串口 if com IsOpen com Close co