从2002年就开始接触Modbus协议,以后陆续在PLC、DOS、Windows、.Net Micro Framework等系统中使用了该协议,在我以前写的一篇博文中详细记载了这一段经历,有兴趣的朋友可以看一看《我的Modbus Slave/Client开发历程(Rtu/AscII/Tcp)》。该协议公开,精简,并且可靠,目前大部分智能仪表,智能模块和一些PLC都采用了该协议,前一段时间有位网友询问相关Modbus的问题,所以这里就以Modbus的实现来来作为.Net MF开发板的串口示例。
本示例包含两部分,一部分运行到开发板上,作为Modbus RTU Slave服务存在;另一部分典型的.Net Framework代码,实现了Modbus RTU Client端功能,可以借助开发板上的Slave服务控制开发板上的LED灯和获取按钮状态。
Slave类的实现如下(具体实现请参见示例源码):
namespace YFSoft.Modbus
{
public class Slave
{
//数据区读写事件
public event ReadDataEventHandler ReadData;
public event WriteDataEventHandler WriteData;
//启动Modbus服务
public void Start(string portName, int baudRate, Parity parity);
//停止Modbus服务
public void Stop();
}
}
调用相对简单,代码如下:
public static void Main()
{
Graphics.Clear(Color.Black);
Graphics.Print("Modbus Rtu Test\r\n");
… …
RtuSlave.ReadData += new ReadDataEventHandler(RtuSlave_ReadData);
RtuSlave.WriteData += new WriteDataEventHandler(RtuSlave_WriteData);
RtuSlave.Start("COM2", 19200, System.IO.Ports.Parity.None);
int index = 0;
while (true)
{
//leds[0].Write(!leds[0].Read());
Graphics.FillRectangle(0, 305, 240, 15, Color.White);
Graphics.DrawString(5, 306, (index++).ToString(), Color.Blue);
Thread.Sleep(1000);
}
//RtuSlave.Stop();
}
比较重要的是下面的代码,它们具体实现读写LED的状态及按钮状态,需要注意的是红牛的开发板和EM-STM3210E的LED有些不同,一个是输出电平为低时点亮,一个是输出电平为高时点亮,相关代码如下:
static void RtuSlave_WriteData(int addr, int size, ref byte[] data)
{
//写LED
if (addr == 0)
{
for (int i = 0; i < leds.Length; i++)
{
#if Redox
leds[i].Write(!((data[1] & 0x1<<i) > 0));
#else
leds[i].Write((data[1] & 0x1 << i) > 0);
#endif
}
}
}
static void RtuSlave_ReadData(int addr, int size, ref byte[] data)
{
if (addr < 2)
{
//读LED
byte bytTemp = 0;
for (int i = 0; i < leds.Length; i++)
{
#if Redox
bytTemp |= (byte)((leds[i].Read() ? 0 : 1) << i);
#else
bytTemp |= (byte)((leds[i].Read() ? 1 : 0) << i);
#endif
}
data[1] = bytTemp;
//读Button
bytTemp = 0;
for (int i = 0; i < buttons.Length; i++)
{
bytTemp |= (byte)((buttons[i].Read() ? 1 : 0) << i);
}
data[3] = bytTemp;
}
}
PC机上的.Net Framework代码实现了一个Modbus Rtu Client类,相关接口如下:
namespace YFSoft.Modbus
{
public class Client
{
public bool Open(string portName, int baudRate, Parity parity);
public int Read(byte Addr, UInt16 DataAddr, UInt16[] DataValue, UInt16 DataNum);
public int Write(byte Addr, UInt16 DataAddr, UInt16[] DataValue, UInt16 DataNum);
}
}
由于.Net Framework代码不是介绍的重点,感兴趣的朋友直接看相关源码(其实该套源码几乎不需要修改,就可以直接成为.Net Micro Framewor的代码,这也正是.Net Micro Framework的魅力之所在)。
下位机机运行后的效果图如下:
注意:红牛代码和EM-STM3210E不同,后者需要注释掉 #define Redox 代码。
上位机代码解压后,直接运行即可,程序的相关参数已经配好,如果启动时,开发板已经正常运行,并且和PC进行了串口连接,则会显示如下画面。按开发板上的按钮,这是按钮状态会有变化,用鼠标单击LED区的鼠标,你会发现开发板上的LED灯会做同步改变。
这应该是关于Modbus示例代码中的重量级示例,因为Client和Slave的源码都涉及到了,并且相关代码不仅仅是示例,也来源于我以前所做的工程项目,所以非常有价值。
下一篇文章将介绍和所做的,就是我们就要把Modbus Client端移植到开发板上运行了,对红牛开发板来说,我们通过COM3的485接口直接控制PLC,不过对EM-STM3210E开发板来说,没有这么爽,它不光没有485接口,并且COM3口也没有引出了,所以要想访问PLC,一般需要中间接一个232转485设备,不管怎样,我们的开发板不仅上可以给PC通信,下也可以和PLC通信了。
-----------------------------------------------------------------------------------------